Pwnable.tw-seethefile
Author: 堇姬Naup
libc
glibc all in one 中沒有 2.23-0ubuntu5
所以去網路上找libc
https://launchpad.net/ubuntu/xenial/i386/libc6/2.23-0ubuntu5
把i386載下來
1 | dpkg -X libc6_2.23-0ubuntu5_i386.deb . |
在libs裡面就有ld跟libc了
patchelf直接patch上去
1 | patchelf --set-interpreter ld-2.23.so seethefile |
IDA 分析
main
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
menu
1 | int menu() |
五種功能
openfile
readfile
writefile
closefile
Exit
Exit的地方會讓你輸入name,並print出來
openfile
1 | int openfile() |
readfile
1 | int readfile() |
writefile
1 | int writefile() |
closefile
1 | int closefile() |
vtable
1 | struct _IO_jump_t |
1 | pwndbg> x/40xw 0xf7fccac0 |
fclose and __fininsh source code
宣告fclose
https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/stdio.h#L213
1 | /* Close STREAM. |
call fclose 會進到 _IO_new_fclose
https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/iofclose.c
1 | int |
首先他call _IO_un_link
將 fp 移出鏈表
之後調用 _IO_FINISH 一樣經過了一堆 macro後,他 call 到 _IO_new_file_finish
https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/fileops.c#L167
1 | void |
他會去刷新buffer,並syscall close
大致上就是
- 從 _IO_list_all 中移除fp
- call vtable 中 _IO_FINISH (_IO_new_file_finish)
- flush buffer
- _IO_SYSCLOSE
- free
如果我要攻擊 2.23 的fclose,可以偽造vtable
修改 vtable ptr指向fake vtable,並將fake vtable上每個ptr都改成system
並且在fp pointer寫上/bin/sh,這樣call fclose 時候會跳到system上,fclose(fp) -> system(fp) -> system(‘/bin/sh’)
分析
首先是Exit的部分有buffer overflow
再來在/proc/self/maps會有整個binary記憶體的狀況,所以可以透過open read write他來leak libc
1 | from pwn import * |
觀察一下記憶體的布局,name在fp上方,能對file structure做操作
1 | .bss:0804B260 public name |
詳細利用見上方,這邊直接看要偽造啥
1 | pwndbg> x/10xg 0x804b260 |
fp 指向heap上的fp,先將fp修改成bss下方的addr,並在bss上偽造fake FILE
1 | pwndbg> x/50xw 0x804c410 |
1 | 'i386':{ |
要偽造
flags = 0xfbaddfff (_IO_IS_FILEBUF 要關掉,來bypass & _IO_IS_FILEBUF)
用分號在下方偽造/bin/sh
vtable 指向 fake vtable addess
1 | ------------- 0x804B260 |
最終利用腳本如下
exploit
local
1 | from pwn import * |
remote
在remote狀況時,需要改一下收libc的地方
1 | from pwn import * |
連上後執行讀檔的binary,輸入 Give me the flag 就可以get flag
1 | $ ls |