ROP (64byte) 문제 3번

2019. 4. 26. 10:52System Hacking/ROP(64byte)

prob


안녕하세요!

오늘은 rop 64byte

3번째 문제를 풀어보도록 할게요!


해당 문제는 제가 위에 올려놓았습니다!

코드는 아래와 같습니다!


char형의 배열 sh에는 "/bin/sh" 문자열이

들어가있네요!


당연히 이를 활용하라고 던져준거겠죠?


그 밑에 nothing 이라는 함수가 있는데

asm volatile("~~~~~~~ ") 

이런 형식으로 적혀있죠?


asm volatile( )은 c언어에서 assembly 코딩을 할 때

쓰이는 함수에요!


그냥 push %rdi

      pop %rdi

     ret 

이 3 가지 어셈블리 명령어가 실행된다고 보시면 되요!

(당연히 이것도 활용을 하라는 것이겠죠?)

 

그리고 vuln( ) 함수가 있습니다!

함수 안을 살펴보니

buf가 16바이트이고

system함수에서 echo(출력해라) "INPUT: " 을!

(system함수 = cmd 창이라고 생각하시면 됩니다!)


근데 이후에 취약점이 바로 터지죠!

버퍼는 16바이트인데 

read 함수로 버퍼에 256 바이트를 쓰네요!



16byte뒤에 ret address 버퍼오버플로우로 조작해서!

rop 64를 해보도록할게요! 


문제의 vuln 함수를

pead로 까보았습니다!


sub rsp,0x10(=16)

16만큼 빼네요! 

코드에 딱 선언한 만큼!


그러면 이론적으로는 

16byte + EBP(8byte) + RET (8byte)겠죠!


32bit였으면

16byte + EBP(4byte) + RET (4byte)였겠지만

64bit는 한번에 8byte의 크기로 움직이니까요!




근데 그래도 정확히 하는 게 좋으니!

검증을 해보도록 하겠습니다!


pwntools에서 제공하는

기능중에서 cyclic을 이용해보겠습니다!


cyclic이 뭔데 cyclic을 쓰려고하냐?

(1) cyclic으로 문자열을 생성해서!


(2)그 문자열을 프로그램에 입력하고


(3) ret_address에 어떠한 문자가 적혀있는지를

cyclic에 넘겨주면 


(4)알아서 얼마나 덮어쓰면 되는지 알려주는 친구라서 쓰려구요!


사용법은

아래와 같이 

pwn cyclic 숫자 


저렇게 입력을 하면 숫자에 적힌 만큼

문자열을 생성해줘요!


저는 숫자에 100을 넣고 

엔터를 치니 아래와 같이 

문자열이 생성됐죠?


자 vuln+42부분이 ret_address이니

여기에 breakpoint를 걸구요!


INPUT에 제가 말한 것 처럼

저 긴 문자열을 입력 값으로 넣어줍니다!


그 다음에 ret_address에 무슨 값이 있는지!

확인하려고 스택의 최상단을 보니!

0x61616167이라고 적혀있죠?


(참고로 64bit라 esp,ebp라고 치면 안돼요 ㅠㅠ)



그러면 다시 gdb에서 exit한 다음에


이번에는 

cyclic -l (붙여넣을 숫자)


이렇게 하면 알아서 offset(거리)를 계산해 줘요!

저는 붙여넣을 숫자에 0x61616167을 넣을거에요!


그 숫자가 ret_address에 있었으니!

ret_address전까지 얼만큼 덮어써야하는지 알아야 하잖아요!


그랬더니 바로 24개만큼 덮어쓰면 된다고

아래에 숫자 24가 출력이 되죠?



자 그러면 바로 exploit code를 작성해 보겠습니다!

pwntools를 사용하겠습니다!


제일 먼저 pwntools 사용한다고 명시!

(from pwn import *)


e와 p라는 변수(=객체)에

 각각

prob3 파일을 읽은 결과와 

실행경로를 저장할 꺼에요!


그리고 raw_input(">>> ")

이 부분은 적어주셔도 되고!

안 적어주셔도 되는데!

gdb로 디버깅 추적하고 싶으시면 적어두세요!


자 그리고 저희의 payload를 처음에는

빈 것 '' 으로 설정을 합니다!


그리고 저희가 말한 덮어써야 할 값

몇 개라고 아까 pwn cyclic을 통해 알아냈죠?

24개라고 했죠?


그러니 a라는 문자열 

(아무 문자열이나 상관 없음)

24개를 넣어줍니다!


그리고 그 다음에는 

좀 낯설 수 있는데!


nothing 함수에서 

어셈블리 코딩부분중에서

필요한 부분만 가져다 쓸거라!


바로 

push rdi

ret 

부분이요!


근데 e.symbols[ ] 

요놈은 뭐냐?


e는 제가 위에서 말한 파일의 정보를 읽어서 기록한 놈!

e.symbol 하게 되면!

파일 정보에서 심볼을 가져와라!

( 심볼을 간략히 말씀드리자면 함수의 이름, 변수의 이름 등등)


여기서는 nothing이라는 함수의 symbol을 가져온거죠!

그래서 이렇게 e.symbol['nothing']

이라고 적으면 nothing 함수의 시작주소가 알아서!

pwntool이 구해줍니다! 


+5를 한 이유는 nothing 함수를 보시면!

nothing +5 부분이 

pop rdi

이기 때문입니다!



그리고 저렇게 주소 값을 다 구한 다음에!

저희가 64bit 환경에 맞게 끔

주소값 little endian으로 안맞춰도!

p64( )를 통해서 쉽게 해결가능해요!


p64(넣고 싶은 주소 값


32bit는

p32(넣고 싶은 주소 값)


그 밑에는

sh[] ="/bin/sh"

에서 배열의 이름 sh 심볼 읽어오고


system 함수도

system 심볼을 읽어오면


저희의 payload가 완성됩니다!


이해를 돕기 위해서 스택 구조를 그려볼게요!


   [우리가 생각하는 스택 구조]


(1)    더미 24byte

     (2)  nothing+5주소 (ret)

      (3) sh 주소 (/bin/sh 인자 =pop rdi)

(4) system 함수  (ret)


return해서 nothing+5로 가면!

esp는 그 때 (3)을 가리킵니다!

(esp가 원래 (2)가리키고 있었는데 ret명령어 pop eip 되면서 내려감)


그리고 (3)을 가리키고 있을 때, 

pop rdi 하니

(3)이 rdi로 pop돼서 인자 세팅이 됩니다!

rdi => 64byte rop에서 1번째 인자


그리고 ret을 system함수로 하니!

system("/bin/sh") 가 완성이 되는거죠!


참고로 함수의 symbol만을 읽어오면 

함수의 인자는 저희가 세팅해줘야 해요!

그 함수만 호출 되는거에요!


밑에 p.readuntil('INPUT:')은

프로그램에서 값을 읽어온다 INPUT:이 나올 때 까지


그리고 p.send( ) 보낸다!

뭘? 저희가 작성한 payload를 인자로!

p.send(payload)!


그리고 이게 성공적으로 되었다면!

shell이 획득되는데,


이 shell과 소통하기 위해서

p.interactive()를 씁니다!


그럼 고생하셨습니다!

'System Hacking > ROP(64byte)' 카테고리의 다른 글

ROP (64byte) 문제 4번  (0) 2019.04.27
ROP (64byte) 문제 2번  (0) 2019.04.24
ROP (64byte) 문제 1번  (0) 2019.04.22