[25] IT 비전공자 [dreamhack] simple-operation문제 풀기
25번째 문제다 가보자구!
풀이를 안보고 gpt랑 같이 풀었는데
ghidra라가 필요해서 당누받아 분석하고
Ghidra는 미국 국가안보국(NSA)에서 개발한 오픈소스 리버스 엔지니어링 도구입니다. 바이너리 파일을 분석하고 디컴파일하는 데 매우 유용하며, 특히 ELF, PE 등 다양한 파일 포맷을 지원하여 리눅스, 윈도우, macOS 환경에서 실행되는 프로그램을 분석할 수 있습니다.
이 후 이 값을 어떻게 알아야 되나 싶은건 더이상 머리가 막혀서 풀이를 찾아봤다
[드림핵] simple-operation 기드라로 프로그램 처음 분석해보기
초보자에게 꼭 나오는 XOR 연산 특징을 이용한 문제를 풀어봅시다.
velog.io
https://hannahsecurity.tistory.com/entry/%EB%93%9C%EB%A6%BC%ED%95%B5Dreamhack-simple-operation
[드림핵(Dreamhack)] simple-operation
아래처럼 Random number를 주고 input을 받은 다음 result를 출력하는 프로그램이다 아이다로 역 연산 해보면 input이 0x7d1c4b0a^ran이어야한다. input은 real time으로 계산해서 넘기면 된다. result가 a0b4c1d7이
hannahsecurity.tistory.com
https://eunginius.tistory.com/entry/Dreamhack-Beginner-simple-operation
[Dreamhack] Beginner: simple-operation
simple-operation Description 우리의 친구 아모가 미션을 주었습니다. "내가 원하는 결과가 나오도록 값을 입력해 줘!" 주어진 바이너리를 분석하고 알맞은 값을 입력하면 플래그가 출력됩니다. 플래그
eunginius.tistory.com
하...엔터를 눌러도 다음 화면으로 안넘어가고 그냥 줄바꿈이 되버린다...
하 왜 왜 input 값을 구해왔는데 입력을 할 수 없니...
2024-10-22 다시 문제 풀러 왔다..
IDA로 디컴파일했다..이거 너무 편한데..습관들이면 안된다.. 어셈블리어랑 친해져야한다ㅏㅣㅏㅏ아ㅏㅏ
int __fastcall main(int argc, const char **argv, const char **envp)
{
char s1[9]; // [rsp+6h] [rbp-3Ah] BYREF
char s[9]; // [rsp+Fh] [rbp-31h] BYREF
int v6; // [rsp+18h] [rbp-28h] BYREF
int v7; // [rsp+1Ch] [rbp-24h] BYREF
char *s2; // [rsp+20h] [rbp-20h]
int fd; // [rsp+2Ch] [rbp-14h]
void *buf; // [rsp+30h] [rbp-10h]
int v11; // [rsp+38h] [rbp-8h]
int i; // [rsp+3Ch] [rbp-4h]
v7 = 0;
v6 = 0;
v11 = 0;
initialize(argc, argv, envp);
buf = malloc(0x45uLL);
fd = open("./flag", 0);
read(fd, buf, 0x45uLL);
close(fd);
get_rand_num(&v6);
printf("Random number: %#x\n", v6);
printf("Input? ");
__isoc99_scanf("%d", &v7);
v11 = v6 ^ v7;
snprintf(s, 9uLL, "%08x", v6 ^ v7);
for ( i = 0; i <= 7; ++i )
s1[i] = s[7 - i];
printf("Result: %s\n", s1);
s2 = "a0b4c1d7";
if ( !strcmp(s1, "a0b4c1d7") )
{
puts("Congrats!");
puts((const char *)buf);
}
else
{
puts("Try again");
}
return 0;
}
코드의 흐름을 먼저 보자.
17-20: flag 파일을 열어서 파일 디스크립터를 fd 변수에 담는다. 45바이트만큼 읽어서 buf 변수에 받고 다시 닫는다.
21: 난수를 v6에 저장한다.
24: v7에는 사용자 입력값을 받는다.
25: v6 ^ v7 은 XOR 연산을 의미한다.
26: snprintf 함수는 출력 결과를 문자열 버퍼에 저장하는 함수이다. 버퍼의 크기를 지정하여 버퍼 오버플로우를 방지하는데 여기서는 9uLL로 지정했다. 9는 버퍼의 크기이고, uLL은 unsigned long long 타입임을 나타낸다. 추가로 %08x는 16진수로 출력하고 최소 8자리를 출력하며 부족한 자릿수는 0으로 채운다는 걸 의미한다.
27-28: 그 결과가 담긴 s 문자열을 s1에 거꾸로 담는다.
31: 그 결과가 a0b4c1d7과 일치하는지 판별한다.
즉, 랜덤값과 입력값을 XOR 연산한 결과가 a0b4c1d7과 일치하게 만들면 된다.
출처 ㅣ https://eunginius.tistory.com/entry/Dreamhack-Beginner-simple-operation
그리고 for문을 통해 s1 배열은 s 배열을 뒤집어서 저장하고 있다. 그런데 이 s1을 a0b4c1d7과 비교해서
분기함으로(같으면 Congrats!, 다르면 Try again) s는(buffer_for_random xor input) = 7dc14b0a가 되어야 한다.
출처ㅣ https://hyunhe2e.tistory.com/m/132
해서 변경하는데 계속 입력이 안된다...
91ea9fff xor 7d1c4b0a -> 10진수 변경한걸 입력해도 그냥 줄바꿈 된다
https://eunginius.tistory.com/entry/Dreamhack-Beginner-simple-operation
결국pwn 모듈을 사용했다.
from pwn import *
# 지정 호스트의 지정 포트로 원격 접속
r = remote("host3.dreamhack.games", <포트번호>)
# 서버에서 rand 값 받기
r.recvuntil(b"number: ")
rand = r.recvn(10)
print("rand : ", rand)
# 16진수로 변환한 후 XOR 연산
x = int(rand, 16) ^ 0x7d1c4b0a
# 문자열로 변환 후 바이트 형식으로 인코딩
x = str(x).encode()
# Input?이란 문자열이 나올 때 값을 전송
r.sendlineafter(b"Input? ", x)
# 프로그램 제어(입출력 등)를 사용자에게 넘김
r.interactive()
코드 출처ㅣ https://eunginius.tistory.com/entry/Dreamhack-Beginner-simple-operation