---
# System prepended metadata

title: swsec110_hw11_writeup
tags: [swsec]

---

---
title: swsec110_hw11_writeup
date: 2022-01-13
tags: swsec
---
# swsec110 hw11 writeup
學號: 309553032

網頁版：
https://hackmd.io/@johnson08/rk7CuWont

本次作業主要分成以下部分：
- [leak libc address](#leak-libc-address)
    - 減少`_IO_write_base`的方式利用 partial overwrite, libc自動補 1 byte `\x00`
- [hijack vtable](#hijack-vtable)
    - 將合用的 one_gadget (offset 0xe6c7e) 塞入 fwrite 會使用到的、vtable entry指向的 `_IO_file_overflow` 
        - 雖然理論上會先call到`_IO_file_xsputn`，應該也可以覆蓋這邊，但不知為何會造成segmentation fault
- [remote buffer flush](#remote-buffer-flush)
    - local 的程式在 remote 無法直接 work 的原因是 buffer 沒有 flush 掉；填滿 buffer 或者換行可以flush, 這邊採用前者
- [catch the flag](#catch-the-flag)

## leak libc address
### libc 位址資訊位於 created file structure

由於此題不像 labs 有直接給 libc functions 位址，也不像 pwn2 可以 free unsorted bin 以 leak main arena, 而是一開始就空空如也，但基於 UAF 的精神還是翻了一下各個 chunks 

翻著翻著就看到了某個很像屬於 libc 的東西
![](https://i.imgur.com/gPJIWfe.png)

檢視其 file structure
![](https://i.imgur.com/LqCVL2l.png)

發現他是 stderr, 這呼應到上課所提到的，glibc會把所有 file structure 串起來，以便程式終止時 flush buffers

總之，想要 leak 的目標在這邊(雖然之後發現不是)

有個可控的 file structure, 又有 fwrite 可用之，看似滿足任意讀的架構，但仔細想了一下，heap的位址也沒有，即便可以任意讀，也無法指定到該 chunk 

### hint: _IO_IS_APPENDING

由出題的hint谷歌此flag可以如何達到leak，找到以下關鍵：
![](https://i.imgur.com/0bPGVsZ.png)
(src: https://n0va-scy.github.io/2019/09/21/IO_FILE/)

trace code 以及理解的篇幅在此文章皆有提到。綜上，複寫 fp 須達到三件事：
- fileno: 1 (stdout)
- flags: 0x1800
- `_IO_write_base` 改小

至此，想法如下：由於不知道`_IO_write_base`位置，上述三件事無法透過一次的 overwrite 完成；須先進行一次 overwrite, 將較高位址的 fileno 覆蓋為 1, 再 call 一次 `fwrite(note_buf, 1, BUF_SIZE, fp);`還原看起來比較資訊有效的 io read/write pointers, 再透過 (hint) partial overwrite 將想要讀取的位址指定到想要讀的地方
![](https://i.imgur.com/yUf7rP7.png)

至此，fileno成功地被覆蓋為1, 但再執行一次 fwrite() 後，發現本來想要的酷酷的 chain 當然也被覆蓋掉了，因為是在 fileno 前面啊...
![](https://i.imgur.com/BsxzKpv.png)

不過，就算 chain 可以被保留，fp 在遞增一個 buffer size 之後已經到遙遠的下方了，看看此時如果照原本想法 overwrite 可以得到什麼：
![](https://i.imgur.com/kc8YKu8.png)
![](https://i.imgur.com/GOawHI6.png)

雖然不知道`_IO_wfile_jumps`是什麼，但能夠幫助我得到 libc 就對了，就照原訂計畫去 overwrite

實驗幾次後，發現overwrite的數值後面會再被補 null byte, 那麼退而求其次，讓 null bytes 被補到 `_IO_write_base` 的 lowerbyte, 以此達到減小`_IO_write_base` 的目的
![](https://i.imgur.com/TPGe7Pm.png)

![](https://i.imgur.com/akd7Kzj.png)

![](https://i.imgur.com/CvsMQyN.png)
看到`_IO_write_base`位址，減去其elf symbol offset 即可得到 libc 位址！
![](https://i.imgur.com/1nUJ9Eb.png)

![](https://i.imgur.com/cTQYXwK.png)

## hijack vtable

目標是將 `_IO_file_overflow` 改成 one_gadget
![](https://i.imgur.com/yYKOKKz.png)
位於 `_IO_file_jumps + 0x18`

在 lab2,3 中，我們透過 fread() 達到任意寫，而這邊是 fwrite 任意寫。

google fwrite 怎麼任意寫
![](https://i.imgur.com/viwWSVW.png)
(src: https://xz.aliyun.com/t/5853#toc-6)
好像突然想起 fwrite 是一件 trivial 的事情，只要控來源目的就可以達成啊。
是這樣嗎？
![](https://i.imgur.com/istsEWR.png)
覆蓋 `_IO_write_ptr`, `_IO_write_end` 的話，其前面的資料也會被覆蓋掉，write的來源就不明了。但這邊還是先遵照谷哥指示：

![](https://i.imgur.com/6dgMElu.png)

這邊卻發現好像是可控的區域!? 但是不知道這是哪部分

找一下 file structure, 也無法看出原因
![](https://i.imgur.com/zG7nTCe.png)

實測幾次能改到的地方，發現是 payload 起頭的字串當作來源，於是修改 payload 如下：
![](https://i.imgur.com/bKl0nzN.png)

![](https://i.imgur.com/PwXvrg4.png)
成功塞成 one_gadget 了!

然而執行到這邊，會發現仍然無法過，看來是 one_gadget 用錯，條件不符合

![](https://i.imgur.com/ONFsMgA.png)

事實上如果三個 gadget 都直接硬塞，仍然沒有一個能 work, 

那麼來仔細檢視一下以上條件，在程式到 segmentation fault 時， regs 裡面有什麼是可控的

![](https://i.imgur.com/88ZO0jX.png)
第一個 gadget 指定 r12, r15 址或值須為 null, 查看 regs, r15 已經有 null, r12 是一堆字串A, 這代表把先前用A覆蓋的方式改成用`\x00`覆蓋，基本上應該不影響前面exploit, 且可以滿足這裡的條件：

![](https://i.imgur.com/8qKu4Jm.png)
成功拿到 shell!

## remote buffer flush

如果直接把local測試好的程式跑在 remote 上，會直接卡住：
![](https://i.imgur.com/bFpftaO.png)

我的第一個做法是將 process.interactive()塞在程式中的故處，看到底是那裡卡了
![](https://i.imgur.com/ytS8UAI.png)

重複測試，發現在要 leak libc 的部分時不會卡住，但也沒有照預期的把 libc leak 出來，而是直接 loop 下一次選項清單
![](https://i.imgur.com/EELBhoZ.png)

說來難以相信，我沒有先想到 buffer flush 的問題，而是一邊想著到底是刪小一邊狂按3下去直到libc leak出來...

![](https://i.imgur.com/jGxuKw6.png)

後來想到上課提到，要將 buffer 內容輸出，1是掃到換行字元，2是buffer滿了會被flush, 既然我是重複 write() 直到 flush, 那就暴力的寫個回圈吧...
![](https://i.imgur.com/nlESw9h.png)

## catch the flag

![](https://i.imgur.com/oKUkYbJ.png)