基于buuctf/rip
寻找puts函数的动态链接
### readelf
readelf -S filename 查看session header找到相关重定向表
.plt 0000000000401020
.got 0000000000403ff0
.got.plt 0000000000404000
### gdb调试
断点:b *0x401151
[-------------------------------------code-------------------------------------]
0x401143 <main+1>: mov rbp,rsp
0x401146 <main+4>: sub rsp,0x10
0x40114a <main+8>: lea rdi,[rip+0xeb3] # 0x402004
=> 0x401151 <main+15>: call 0x401030 <puts@plt>
0x401156 <main+20>: lea rax,[rbp-0xf]
0x40115a <main+24>: mov rdi,rax
0x40115d <main+27>: mov eax,0x0
0x401162 <main+32>: call 0x401050 <gets@plt>
Guessed arguments:
arg[0]: 0x402004 ("please input")
(1)si
[-------------------------------------code-------------------------------------]
0x401021: xor eax,0x2fe2
0x401026: jmp QWORD PTR [rip+0x2fe4] # 0x404010
0x40102c: nop DWORD PTR [rax+0x0]
=> 0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
| 0x401036 <puts@plt+6>: push 0x0
| 0x40103b <puts@plt+11>: jmp 0x401020
| 0x401040 <system@plt>: jmp QWORD PTR [rip+0x2fda] # 0x404020 <system@got.plt>
| 0x401046 <system@plt+6>: push 0x1
|-> 0x401036 <puts@plt+6>: push 0x0
0x40103b <puts@plt+11>: jmp 0x401020
0x401040 <system@plt>: jmp QWORD PTR [rip+0x2fda] # 0x404020 <system@got.plt>
0x401046 <system@plt+6>: push 0x1
JUMP is taken
(3)x/2w 0x404018
可以发现指向了一个不知道哪里的地方,此时是因为是第一次寻找puts函数所以指向的地址上没有需要的puts函数地址(这个点很重要)
0x404018 <puts@got.plt>: 0x00401036 0x00000000
(3)可以发现jmp执行直接进入了下一条指令push而不是跳转
jmp指向的地址0x404018处于.got.plt表内,说明puts函数的寻找先到.got.plt表内寻找
[-------------------------------------code-------------------------------------]
0x401026: jmp QWORD PTR [rip+0x2fe4] # 0x404010
0x40102c: nop DWORD PTR [rax+0x0]
0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
=> 0x401036 <puts@plt+6>: push 0x0
0x40103b <puts@plt+11>: jmp 0x401020
0x401040 <system@plt>: jmp QWORD PTR [rip+0x2fda] # 0x404020 <system@got.plt>
0x401046 <system@plt+6>: push 0x1
0x40104b <system@plt+11>: jmp 0x401020
(4)si
jmp指向的地址0x404020处于.plt表起始,说明跳转到.plt表内
[-------------------------------------code-------------------------------------]
0x40102c: nop DWORD PTR [rax+0x0]
0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
0x401036 <puts@plt+6>: push 0x0
=> 0x40103b <puts@plt+11>: jmp 0x401020
| 0x401040 <system@plt>: jmp QWORD PTR [rip+0x2fda] # 0x404020 <system@got.plt>
| 0x401046 <system@plt+6>: push 0x1
| 0x40104b <system@plt+11>: jmp 0x401020
| 0x401050 <gets@plt>: jmp QWORD PTR [rip+0x2fd2] # 0x404028 <gets@got.plt>
|-> 0x401020: push QWORD PTR [rip+0x2fe2] # 0x404008
0x401026: jmp QWORD PTR [rip+0x2fe4] # 0x404010
0x40102c: nop DWORD PTR [rax+0x0]
0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
JUMP is taken
(5)si
[-------------------------------------code-------------------------------------]
0x40101a: add BYTE PTR [rax],al
0x40101c: add BYTE PTR [rax],al
0x40101e: add BYTE PTR [rax],al
=> 0x401020: push QWORD PTR [rip+0x2fe2] # 0x404008
0x401026: jmp QWORD PTR [rip+0x2fe4] # 0x404010
0x40102c: nop DWORD PTR [rax+0x0]
0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
0x401036 <puts@plt+6>: push 0x0
(6)x/2w 0x404008(因为是QWORD,64位数据,而每位是32位的数据,64位数据就需要两个位置)
0x404008: 0xf7ffe2c0 0x00007fff
(7)si
jmp指向的地址处于.got.plt表内,说明又转到.got.plt表内一个地址上指向的地址
[-------------------------------------code-------------------------------------]
0x40101d: add BYTE PTR [rax],al
0x40101f: add bh,bh
0x401021: xor eax,0x2fe2
=> 0x401026: jmp QWORD PTR [rip+0x2fe4] # 0x404010
| 0x40102c: nop DWORD PTR [rax+0x0]
| 0x401030 <puts@plt>: jmp QWORD PTR [rip+0x2fe2] # 0x404018 <puts@got.plt>
| 0x401036 <puts@plt+6>: push 0x0
| 0x40103b <puts@plt+11>: jmp 0x401020
|-> 0x7ffff7fdd400: push rbx
0x7ffff7fdd401: mov rbx,rsp
0x7ffff7fdd404: and rsp,0xfffffffffffffff0
0x7ffff7fdd408: sub rsp,0x240
JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe198 --> 0x7ffff7ffe2c0 --> 0x0 这里就是压入了 0xf7ffe2c0 和 0x00007fff
0008| 0x7fffffffe1a0 --> 0x0
0016| 0x7fffffffe1a8 --> 0x401156 (<main+20>: lea rax,[rbp-0xf])
0024| 0x7fffffffe1b0 --> 0x0
0032| 0x7fffffffe1b8 --> 0x0
0040| 0x7fffffffe1c0 --> 0x1
0048| 0x7fffffffe1c8 --> 0x7ffff7df16ca (mov edi,eax)
0056| 0x7fffffffe1d0 --> 0x0
[------------------------------------------------------------------------------]
(虽然确实压入了数据,但是该数据在后面调试中发现会被覆盖掉,所以不知道该数据的作用是什么。。。)
(不过按照地址来看,这段数据应该是属于ld.so的数据)
(8)x/2w 0x404010
0x404010: 0xf7fdd400 0x00007fff
(9)si
此时跳转到/lib64/ld-linux-x86-64.so.2的实际地址了
[-------------------------------------code-------------------------------------]
0x7ffff7fdd3f2: ret
0x7ffff7fdd3f3: data16 cs nop WORD PTR [rax+rax*1+0x0]
0x7ffff7fdd3fe: xchg ax,ax
=> 0x7ffff7fdd400: push rbx 可以发现成功跳转到 0xf7fdd400 和 0x00007fff指向的地址
0x7ffff7fdd401: mov rbx,rsp
0x7ffff7fdd404: and rsp,0xfffffffffffffff0
0x7ffff7fdd408: sub rsp,0x240
0x7ffff7fdd40f: mov QWORD PTR [rsp],rax
(10)多个ni后
[-------------------------------------code-------------------------------------]
0x7ffff7fdd46d: mov rsp,rbx
0x7ffff7fdd470: mov rbx,QWORD PTR [rsp]
0x7ffff7fdd474: add rsp,0x18
=> 0x7ffff7fdd478: jmp r11
| 0x7ffff7fdd47b: nop DWORD PTR [rax+rax*1+0x0]
| 0x7ffff7fdd480: push rbx
| 0x7ffff7fdd481: mov rbx,rsp
| 0x7ffff7fdd484: and rsp,0xffffffffffffffc0
|-> 0x7ffff7e3fb70 <puts>: push r14 这里要开始转到实际puts地址开始执行了
0x7ffff7e3fb72 <puts+2>: push r13
0x7ffff7e3fb74 <puts+4>: push r12
0x7ffff7e3fb76 <puts+6>: push rbp
JUMP is taken
(11)si后执行info symbol $pc
puts in section .text of /lib/x86_64-linux-gnu/libc.so.6 说明确实是处于系统库的puts函数实际地址
(12)finish跳出puts函数,执行x/2w 0x404018
可以发现此时在0x404018这个地址上不再是原来储存的地址,储存的反而是指向puts在系统库内的实际地址
0x404018 <puts@got.plt>: 0xf7e3fb70 0x00007fff
简要流程图
学习于:
https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html