Introducción
En la parte 2 pudo identificar el acceso a traves del servicio TELNET usando credenciales de acceso por defecto admin:admin y tambien el servicio HTTP en el puerto 80 que es ofrecido por el binario /bin/goahead, en esta parte 3 iniciará a probar las diferentes funcionalidades de la interfaz WEB del mini router y la identificación de vulnerabilidades a traves del análisis estatico del binario usando un desemsamblador.
Preparando el entorno de depuración
En el articulo anterior Parte 2 pudimos observar la arquitectura del binario /bin/goahead
goahead: ELF 32-bit LSB executable, MIPS, MIPS-II version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
Como iniciará un proceso de análisis estático y dinámico necesitará algunos recursos para poder depurar este programa.
Puede hacer uso de los siguientes recursos:
- gdb-server para la arquitectura MIPSLE que puede descargar de aquí
- Puede hacer uso del proyecto debugger que no es mas que una imagen docker con algunos recursos importantes para la depuración como el cliente gdb multiarch, Ropgadget etc.
- para facilidad de la depuración puede descargar el directorio raiz del firmware de A5-V11 para la carga de librerias y simbolos(opcional) puede aprovechar montar una usb en el mini router esta será la opcion que usará para enviar archivos de maquina depuradora a mini router.
- Haga uso del siguiente script para ejecutarlo con gdb-multiarch.
set architecture mips
set endian little
target remote <IP-A5-V11>:<PORT_GDB_DEBUGGER>
#Path of the target binary on the client gdb machine
#file <GDB client path>/goahead
file /mnt/debug/sysroot-A5-V11/bin/goahead
# This should point to the target binary path on the router
#set remote exec-file <router binary path> /bin/goahead·
set sysroot /mnt/debug/sysroot-A5-V11/
set remote exec-file /bin/goahead
Ahora puede correr el el siguiente comando desde la terminal telnet del A5-V11 una vez descargado el binario de gdb-server, para iniciar el servidor de depuración.
# ./gdbserver.mipsle 0.0.0.0:23947 --attach 648
Attached; pid = 648
Listening on port 23947
Tenga en cuenta que el PID 648 hace referencia al proceso de /bin/goahead esto puede variar en su dispositivo.
Ahora inicie su contenedor docker debugger usando el siguiente comando.
sudo docker run -v /path/A5-V11:/mnt/debug/ -it sasaga/debugger:2.0 shell
Recuerde que /path/ hace referencia a la carpeta donde esta el sys_root descargado del A5-V11 y el archivo script para gdb-multiarch.
Welcome to
____ _
| \ ___| |_ _ _ ___ ___ ___ ___
| | | -_| . | | | . | . | -_| _|
|____/|___|___|___|_ |_ |___|_|
|___|___|
By: @sasaga92
08003498 10 b5 push { r4, lr }
0800349a 88 b0 sub sp,#0x20
0800349c 00 23 movs r3,#0x0
0800349e 00 93 str r3,[sp,#0x0]=>code
.........
080034b0 64 23 movs r3,#0x64
080034ca 20 46 mov status_code_return_strcmp,r4
080034cc 08 b0 add sp,#0x20
080034ce 10 bd pop { r4, pc }
[+] Opening shell...
⚡ root@b799ff9343cb /home/root ls /mnt
debug
⚡ root@b799ff9343cb /home/root ls /mnt/debug
✘ ⚡ root@b799ff9343cb /home/root cat /mnt/debug/dbgscript_A5-V11
set architecture mips
set endian little
#target remote <router IP>:23947
target remote 192.168.100.1:23947
#Path of the target binary on the client gdb machine
#file <GDB client path>/goahead
file /mnt/debug/sysroot-A5-V11/bin/goahead
# This should point to the target binary path on the router
#set remote exec-file <router binary path> /usr/bin/goahead·
set sysroot /mnt/debug/sysroot-A5-V11/
set remote exec-file /bin/goahead
Finalmente ejecute el script y conectese al servidor GDB.
⚡ root@b799ff9343cb /mnt/debug gdb-multiarch -x dbgscript_A5-V11
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
pwndbg: loaded 141 pwndbg commands and 42 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $ida GDB functions (can be used with print/break)
The target architecture is set to "mips".
The target is set to little endian.
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x2ab440bc in ?? ()
Reading /lib/libc.so.0 from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /lib/libnvram.so.0 from remote target...
Reading /lib/libhpbase.so.0 from remote target...
Reading /lib/libhpaal.so.0 from remote target...
Reading /lib/ld-uClibc.so.0 from remote target...
Reading /lib/ld-uClibc.so.0 from remote target...
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
------- tip of the day (disable with set show-tips off) -------
Calling functions like call (void)puts("hello world") will run all other target threads for the time the function runs. If you want only the current thread to run for the function call, use set scheduler-locking on
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────────
V0 0x202
V1 0x0
A0 0x4
A1 0x4c2c18 ◂— 0x8
A2 0x4c2d08 ◂— 0x0
A3 0x1
T0 0x0
T1 0x20200909 ('\t\t ')
T2 0x6f6f9c00
T3 0x0
T4 0x18
T5 0x200
T6 0x100
T7 0x3
T8 0x1
T9 0x2ab44080 ◂— lui $gp, 9 /* '\t' */
S0 0x4b9498 ◂— 0x0
S1 0x8
S2 0x0
S3 0x1
S4 0x4c3018 ◂— 0x0
S5 0x4c2d08 ◂— 0x0
S6 0x4c2c18 ◂— 0x8
S7 0x499cfc (socketMax) ◂— 0x1
S8 0x1
GP 0x2abd65c0 ◂— nop
FP 0x0
SP 0x7f912c40 —▸ 0x4a1460 ◂— 0x0
PC 0x2ab440bc ◂— addiu $sp, $sp, 0x20 /* ' ' */
───────────────────────────────────────────────────────────────────────────────────[ DISASM / mips / set emulate on ]───────────────────────────────────────────────────────────────────────────────────
► 0x2ab440bc addiu $sp, $sp, 0x20
0x2ab440c0 lw $t9, -0x7e14($gp)
0x2ab440c4 beqz $a3, 0x2ab440e0
↓
0x2ab440cc jalr $t9
0x2ab440d0 nop
0x2ab440d4 lw $gp, 0x10($sp)
0x2ab440d8 sw $s0, ($v0)
0x2ab440dc addiu $v0, $zero, -1
0x2ab440e0 lw $ra, 0x24($sp)
0x2ab440e4 lw $s0, 0x20($sp)
0x2ab440e8 jr $ra
───────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ sp 0x7f912c40 —▸ 0x4a1460 ◂— 0x0
01:0004│ 0x7f912c44 —▸ 0x499cfc (socketMax) ◂— 0x1
02:0008│ 0x7f912c48 ◂— 0x0
03:000c│ 0x7f912c4c ◂— 0x0
04:0010│ 0x7f912c50 —▸ 0x7f912ca8 ◂— 0x0
05:0014│ 0x7f912c54 —▸ 0x499d00 (socketList) —▸ 0x4b9418 —▸ 0x4b9498 ◂— 0x0
06:0018│ 0x7f912c58 —▸ 0x40f60c (socketInputBuffered+80) ◂— lw $gp, 0x10($sp)
07:001c│ 0x7f912c5c —▸ 0x41c6d4 ◂— lw $gp, 0x10($sp)
─────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────────────────
► 0 0x2ab440bc
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
Nos encontramos conectados al servicio GDB y depurando /bin/goahead ahora esta listo para empezar a depurar, no obstante primero realice un análisis estático del binario para buscar puntos de entrada.
Inyección de comandos en /goform/addRouting
Algo por lo que siempre se debe empezar es por identificar aquellos puntos de acceso por los cuales el cliente final tiene el control de la inserción de datos, es un punto de partida bastante fundamental para empezar a probar.
Vea el modulo /goform/addRouting

Este modulo le permíte agregar su propia regla de rutas en el sistema, puede notarlo cuando escriba la regla la aplíque y vea la consola UART Serial, la cual imprime mensajes del sistema.



Entonces puede ver que tanto el destination como el gateway se puede controlar, pero aun no se sabe que sucede por debajo de capó, asi que úse el desensamblador y busque el pedazo de código que se encarga de manejar esta información.
El bloque de codigo encargado de manejar, esta funcionalidad esta denominado con el nombre de sub_420674, vea el pseudocodigo generado.
00420674 int32_t sub_420674(int32_t* arg1)
00420674 {
004206c4 void var_630;
004206c4 memset(&var_630, 0, 0x100);
004206e0 char var_530;
004206e0 memset(&var_530, 0, 0x100);
00420700 int32_t $v0 = websGetVar(arg1, "dest", 0x44f5c8);
00420720 int32_t $v0_1 = websGetVar(arg1, "hostnet", 0x44f5c8);
00420764 char* $s6 = websGetVar(arg1, &*"lan_netmask"[4], 0x44f5c8);
00420784 char* $s5 = websGetVar(arg1, &*"wan_gateway"[4], 0x44f5c8);
004207a4 char* $s3 = websGetVar(arg1, "interface", 0x44f5c8);
004207a0 char* $v0_5 = websGetVar(arg1, "custom_interface", 0x44f5c8);
004207c0 int32_t $v0_6 = websGetVar(arg1, "comment", 0x44f5c8);
004207d0 int32_t var_2c = $v0_6;
004207cc if ($v0 != 0)
004207cc {
004207e0 strcat(&var_630, 0x44fc38); // {"route add "}
004207fc int32_t $v0_7 = strcmp($v0_1, 0x44fdf4); // {"net"}
0042080c void* $a0_11 = &var_630;
00420808 if ($v0_7 == 0)
00420808 {
004209f8 strcat($a0_11, 0x44fc00); // {"-net "}
00420a10 strcat(&var_630, $v0);
00420a2c strcat(&var_630, 0x44fc58); // {" "}
00420a30 }
0042081c else
0042081c {
0042081c strcat($a0_11, 0x44fbf8); // {"-host "}
00420834 strcat(&var_630, $v0);
00420850 strcat(&var_630, 0x44fc58); // {" "}
00420854 }
00420860 if ((($v0_7 == 0 && ((int32_t)*(int8_t*)$s6) == 0) || ($v0_7 != 0 && ((int32_t)*(int8_t*)$s6) == 0)))
00420860 {
00420870 $s6 = "255.255.255.255";
0042087c if (((int32_t)*(int8_t*)$s5) == 0)
0042087c {
0042088c label_42088c:
0042088c $s5 = "0.0.0.0";
00420898 if (((int32_t)*(int8_t*)$s3) != 0)
00420898 {
00420898 goto label_4208ac;
00420898 }
00420898 goto label_420aa0;
00420898 }
00420a84 label_420a84:
00420a84 sprintf(&var_630, 0x44fc90, &var_630, $s5); // {"%s gw %s"}
00420a94 char* $s2_1;
00420a94 int32_t $t9_1;
00420a94 if (((int32_t)*(int8_t*)$s3) != 0)
00420a94 {
004208ac label_4208ac:
004208bc $t9_1 = 0x41da14;
004208c0 if (strcmp($s3, 0x450874) == 0) // {"WAN"}
004208c0 {
004208c0 goto label_420ab8;
004208c0 }
004208e0 if (strcmp($s3, 0x44fc4c) != 0) // {"Custom"}
004208e0 {
00420d40 $s2_1 = getLanIfName();
00420d3c goto label_42090c;
00420d3c }
004208e8 $v0_6 = ((int32_t)*(int8_t*)$v0_5);
004208f4 $s2_1 = $v0_5;
004208f0 if ($v0_6 != 0)
004208f0 {
004208f0 goto label_42090c;
004208f0 }
004208f0 }
00420aa0 else
00420aa0 {
00420aa0 label_420aa0:
00420aa0 $t9_1 = 0x41dba8;
00420aa4 $s3 = &data_44faf4;
00420ab8 label_420ab8:
00420ab8 $s2_1 = $t9_1();
0042090c label_42090c:
0042090c sprintf(&var_630, 0x44fc18, &var_630, $s2_1); // {"%s dev %s "}
00420928 strcat(&var_630, 0x44fc54); // {"2>&1 "}
00420940 puts(&var_630);
0042095c int32_t $v0_12 = popen(&var_630, 0x44e378); // {"r"}
00420978 fgets(&var_530, 0x100, $v0_12);
00420990 int32_t $a1_2;
00420990 int32_t $a2_3;
00420990 $a1_2 = pclose($v0_12);
004209a0 int32_t* $a0_37;
004209a0 char* $a1_6;
004209a0 int32_t $a2_18;
004209a0 if (((int32_t)var_530) != 0)
004209a0 {
00420ce4 websHeader(arg1, $a1_2, $a2_3);
00420cf0 $a0_37 = arg1;
00420cfc $a1_6 = "<h1>Add routing failed:<br> %s<h…";
00420d04 $a2_18 = &var_530;
00420d04 }
004209b4 else
004209b4 {
004209b4 int32_t $v0_13 = nvram_bufget(0, 0x44fbcc); // {"RoutingRules"}
004209c4 int32_t $a1_3 = $v0_13;
004209d0 char var_430;
004209d0 char* $a0_22;
004209d0 int32_t (* const $t9_2)();
004209d0 if (($v0_13 == 0 || ($v0_13 != 0 && ((int32_t)*(int8_t*)$v0_13) == 0)))
004209d0 {
004209dc $t9_2 = memset;
004209e0 $a0_22 = &var_430;
004209e8 $a1_3 = 0;
004209e8 }
004209d0 if (($v0_13 != 0 && ((int32_t)*(int8_t*)$v0_13) != 0))
004209d0 {
00420ac0 $t9_2 = strncpy;
00420ac4 $a0_22 = &var_430;
00420ac4 }
00420ac8 $t9_2($a0_22, $a1_3, 0x400);
00420ad8 if (((int32_t)var_430) != 0)
00420ad8 {
00420d50 strcat(&var_430, 0x44fd8c);
00420d4c }
00420b10 sprintf(&var_430, 0x44fe20, &var_430, $v0, $s6, $s5, $s3, $s2_1, $v0_5, var_2c, &_gp); // {"%s%s,%s,%s,%s,%s,%s,%s"}
00420b2c nvram_bufset(0, 0x44fbcc, &var_430); // {"RoutingRules"}
00420b44 int32_t $a1_5;
00420b44 int32_t $a2_8;
00420b44 $a1_5 = nvram_commit(0);
00420b78 int32_t $a2_10 = websWrite(arg1, "<h3>Add routing table:</h3><br>\n", websHeader(arg1, $a1_5, $a2_8));
00420b88 if (((int32_t)var_530) == 0)
00420b88 {
00420d18 websWrite(arg1, &*"cat /dev/null > %s"[0x10], &var_530);
00420d14 }
00420b9c else
00420b9c {
00420b9c websWrite(arg1, "Success", $a2_10);
00420b9c }
00420bb8 websWrite(arg1, "Destination: %s<br>\n", $v0);
00420bd4 websWrite(arg1, "Host/Net: %s<br>\n", $v0_1);
00420bf0 websWrite(arg1, "Netmask: %s<br>\n", $s6);
00420c0c websWrite(arg1, "Gateway: %s<br>\n", $s5);
00420c28 websWrite(arg1, "Interface: %s<br>\n", $s3);
00420c44 websWrite(arg1, "True Interface: %s<br>\n", $s2_1);
00420c54 if (((int32_t)*(int8_t*)$v0_5) != 0)
00420c54 {
00420d70 websWrite(arg1, "Custom_interface %s<br>\n", $v0_5);
00420d70 }
00420c64 $a2_18 = var_2c;
00420c68 $a1_6 = "Comment: %s<br>\n";
00420c6c $a0_37 = arg1;
00420c6c }
00420c70 $a1_6 = websWrite($a0_37, $a1_6, $a2_18);
00420c88 websFooter(arg1, $a1_6, $a2_18);
00420ca0 $v0_6 = websDone(arg1, 0xc8);
00420ca4 }
00420ca4 }
00420860 if ((($v0_7 == 0 && ((int32_t)*(int8_t*)$s6) != 0) || ($v0_7 != 0 && ((int32_t)*(int8_t*)$s6) != 0)))
00420860 {
00420a58 sprintf(&var_630, 0x44fc08, &var_630, $s6); // {"%s netmask %s"}
00420a68 if (((int32_t)*(int8_t*)$s5) != 0)
00420a68 {
00420a68 goto label_420a84;
00420a68 }
00420a68 goto label_42088c;
00420a68 }
00420a58 }
00420cd4 return $v0_6;
00420cd4 }
El bloque de codigo que puede interesarle es el siguiente:
0042090c sprintf(&var_630, 0x44fc18, &var_630, $s2_1); // {"%s dev %s "}
00420928 strcat(&var_630, 0x44fc54); // {"2>&1 "}
00420940 puts(&var_630);
0042095c int32_t $v0_12 = popen(&var_630, 0x44e378); // {"r"}
00420978 fgets(&var_530, 0x100, $v0_12);
00420990 int32_t $a1_2;
00420990 int32_t $a2_3;
00420990 $a1_2 = pclose($v0_12);
Hay un llamado a la funcion popen que pasa los argumentos que se estaban pasando en la petición HTTP.
Ponga un punto de interrupción en 0042095c y envie la peticion HTTP.
Observe el argumento completo de la peticion
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────────
V0 0x3a
V1 0x2abd19f4 ◂— 'route add -host ThiIsDest gw ThisIsGateway dev br0 2>&1 \n\n'
A0 0x7f912228 ◂— 'route add -host ThiIsDest gw ThisIsGateway dev br0 2>&1 '
*A1 0x44e378 ◂— tlt $zero, $zero, 1 /* 'r' */
A2 0x3a
A3 0x0
T0 0x0
T1 0x61776574 ('tewa')
T2 0x65642079 ('y de')
T3 0x72622076 ('v br')
T4 0x49696854 ('ThiI')
T5 0x80620000
T6 0x100
T7 0x73654473 ('sDes')
T8 0x3
T9 0x2ab2dde0 ◂— lui $gp, 0xb /* '\x0b' */
S0 0x450000 ◂— 'c/ripd.conf '
S1 0x4c19b0 —▸ 0x4c1bb8 ◂— 'host'
S2 0x456484 ◂— 0x307262 /* 'br0' */
S3 0x4d63b0 —▸ 0x4e414c ◂— 0xa0d3e45 ('E>\r\n')
S4 0x4c2ee8 ◂— 'ThiIsDest'
S5 0x4c21c8 ◂— 'ThisIsGateway'
S6 0x44fbe8 ◂— sltiu $s5, $s1, 0x3532 /* '255.255.255.255' */
S7 0x4d6440 ◂— 0x2c4e4100
S8 0x7f912328 ◂— 0x0
GP 0x4a1460 ◂— 0x0
FP 0x0
SP 0x7f9121f8 ◂— 0x0
*PC 0x2ab2dde0 ◂— lui $gp, 0xb /* '\x0b' */
───────────────────────────────────────────────────────────────────────────────────[ DISASM / mips / set emulate on ]───────────────────────────────────────────────────────────────────────────────────
► 0x2ab2dde0 lui $gp, 0xb
0x2ab2dde4 addiu $gp, $gp, -0x7820
0x2ab2dde8 addu $gp, $gp, $t9
0x2ab2ddec addiu $sp, $sp, -0x48
0x2ab2ddf0 sw $ra, 0x44($sp)
0x2ab2ddf4 sw $s6, 0x40($sp)
0x2ab2ddf8 sw $s5, 0x3c($sp)
0x2ab2ddfc sw $s4, 0x38($sp)
0x2ab2de00 sw $s3, 0x34($sp)
0x2ab2de04 sw $s2, 0x30($sp)
0x2ab2de08 sw $s1, 0x2c($sp)
───────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ sp 0x7f9121f8 ◂— 0x0
01:0004│ 0x7f9121fc ◂— 0x0
02:0008│ 0x7f912200 —▸ 0x7f912228 ◂— 'route add -host ThiIsDest gw ThisIsGateway dev br0 2>&1 '
03:000c│ 0x7f912204 —▸ 0x456484 ◂— 0x307262 /* 'br0' */
04:0010│ 0x7f912208 ◂— 0x30433841 ('A8C0')
05:0014│ 0x7f91220c ◂— 0x30303009 ('\t000')
06:0018│ 0x7f912210 ◂— 0x30303030 ('0000')
07:001c│ 0x7f912214 ◂— 0x30300930 ('0\t00')
─────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────────────────
► 0 0x2ab2dde0
Entonces, los argumentos se pasan a popen y esta ejecuta el comando en el sistema, y guarda la salida.
Entonces como no hay ningun filtro de caracteres, o no por ahora identificados, puede pasar a la cadena de destination o gateway cualquier comando antecedido de un ; y terminando con ; inyectando el siguiente payload.
;your-command;

Obtiene el mensaje de la cabecera inicial del mensaje del comando ps, lo cual es bueno, entonces puede cambiar la contraseña del usuario root usando el siguiente payload y acceder al sistema a traves de telnet, y tomar control. del sistema.
Haga uso del siguiente exploit para explotar dicha vulnerabilidad.
Conclusión
Esto ha sido todo en la parte 3, se explotó la primera vulnerabilidad de inyección de comandos en el objeto addRouting identificada en el binario /bin/goahead a traves del análisis estático y dinámico, haciendo uso de GDB y un desensamblador.
Existen inmensas referencias a las funciones DoSystem,system,popen,execl las cuales pueden llevar a diferentes explotaciondes de inyección de comandos dentro del binario /bin/goahead.
Tambien existen algunas vulnerabilidades de desboardamiento de memoria, que se abordaran en partes posteriores como la parte 4 quizás.
siempre puedes invitarme un cafe si lo deseas en https://exploitwriter.io/donaciones/ .
Saludos @sasaga92 Happy Hacking.

Deja un comentario