Linux缓冲区溢出测试中无法覆盖EIP寄存器的问题
背景
我正在Linux环境下创建一个带缓冲区溢出漏洞的应用程序,用于练习漏洞的创建与利用,但目前遇到了瓶颈。
问题描述
尽管输入了约1000个"A"字符,我仍无法覆盖EIP寄存器,程序超出缓冲区限制后也不会崩溃。
代码逻辑是先输入验证码(非易受攻击字段),再请求用户输入邮箱(无验证,为易受攻击字段)。
目标
能够对上述代码进行缓冲区溢出利用,尽可能少地修改其验证合法用户的逻辑(先验证码后邮箱)。
代码
源代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #define PORT 6000 #define BUFFER_SIZE 256 #define CODE "xxxxxxxxxxx" void handle_client(int client_socket) { char buffer[BUFFER_SIZE]; char email[64]; send(client_socket, "Ingrese el código: ", 19, 0); recv(client_socket, buffer, BUFFER_SIZE, 0); if (strncmp(buffer, CODE, strlen(CODE)) == 0) { send(client_socket, "Código correcto. Ingrese su correo: ", 36, 0); recv(client_socket, email, 256, 0); scanf("%s", email); printf("Correo recibido: %s\n", email); } else { send(client_socket, "Código incorrecto.\n", 19, 0); } close(client_socket); } int main() { int server_socket, client_socket; struct sockaddr_in server_addr, client_addr; socklen_t addr_size; server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket < 0) { perror("Error al crear el socket"); exit(1); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("Error al enlazar el socket"); close(server_socket); exit(1); } if (listen(server_socket, 5) < 0) { perror("Error al escuchar en el socket"); close(server_socket); exit(1); } printf("Servidor escuchando en el puerto %d\n", PORT); while (1) { addr_size = sizeof(client_addr); client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &addr_size); if (client_socket < 0) { perror("Error al aceptar la conexión"); continue; } printf("Conexión recibida de %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); handle_client(client_socket); } close(server_socket); return 0; }
编译命令
gcc -m32 -fno-stack-protector source.c -o server -z execstack
实际表现
目前我用GDB调试,输入payload后的寄存器输出如下:
gdb-peda$ info registers eax 0x100 0x100 ecx 0xffffcd20 0xffffcd20 edx 0x100 0x100 ebx 0x4 0x4 esp 0xffffccb8 0xffffccb8 ebp 0x0 0x0 esi 0x0 0x0 edi 0x0 0x0 eip 0xf7fc657b 0xf7fc657b <__kernel_vsyscall+11> eflags 0x246 [ PF ZF IF ] cs 0x23 0x23 ss 0x2b 0x2b ds 0x2b 0x2b es 0x2b 0x2b fs 0x0 0x0 gs 0x63 0x63
我认为EIP寄存器应该变为0x41414141,但实际并非如此。
排查过程
我尝试了多种方法,大部分代码由ChatGPT生成(手动编写耗时太长)。
我尝试过以下函数,均无效:
- gets(编译报错)
- strcpy
- scanf(当前使用的函数)
- strcmp
我还试过编写Windows环境下的代码,用Wine运行,但无法为程序禁用DEP(数据执行保护),导致无法调试。
目前我认为问题出在代码逻辑,而非所用函数或执行方式。
额外疑问
能否通过哈希验证码并对比输入哈希值来进行验证?这种方式会被Ghidra等逆向工具破解吗?
补充信息
2024年10月7日 欧洲中部夏令时 20:35:56
我添加ESP寄存器结果以及提交payload时的GDB输出。
能看到payload,但EIP未被修改。
GDB断点输出
[----------------------------------registers-----------------------------------] EAX: 0x100 EBX: 0x56558ff4 --> 0x3ef0 ECX: 0xffffcd20 ('A' <repeats 200 times>...) EDX: 0x0 ESI: 0xd8fe EDI: 0xf7ffcb60 --> 0x0 EBP: 0xffffce68 --> 0xffffcec8 --> 0x0 ESP: 0xffffcd20 ('A' <repeats 200 times>...) EIP: 0x565562ef (<handle_client+146>: sub esp,0x8) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x565562e4 <handle_client+135>: push DWORD PTR [ebp+0x8] 0x565562e7 <handle_client+138>: call 0x56556100 <recv@plt> 0x565562ec <handle_client+143>: add esp,0x10 => 0x565562ef <handle_client+146>: sub esp,0x8 0x565562f2 <handle_client+149>: lea eax,[ebp-0x148] 0x565562f8 <handle_client+155>: push eax 0x565562f9 <handle_client+156>: lea eax,[ebx-0x1f9a] 0x565562ff <handle_client+162>: push eax [------------------------------------stack-------------------------------------] 0000| 0xffffcd20 ('A' <repeats 200 times>...) 0004| 0xffffcd24 ('A' <repeats 200 times>...) 0008| 0xffffcd28 ('A' <repeats 200 times>...) 0012| 0xffffcd2c ('A' <repeats 200 times>...) 0016| 0xffffcd30 ('A' <repeats 200 times>...) 0020| 0xffffcd34 ('A' <repeats 200 times>...) 0024| 0xffffcd38 ('A' <repeats 200 times>...) 0028| 0xffffcd3c ('A' <repeats 200 times>...) [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x565562ef in handle_client ()
ESP寄存器输出(命令:x/100x $esp)
0xffffcd20: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd28: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd30: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd38: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd40: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd48: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd50: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd58: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd60: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd68: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd70: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd78: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0xffffcd80: 0x41 0x41 0x41 0x41
2024年10月7日 欧洲中部夏令时 22:11:21
正如dbush所说,buffer可能在栈上位于email之后,验证后确实如此。
编译命令
gcc -g -m32 -fno-stack-protector testlin.c -o server -z execstack
变量内存地址
gdb-peda$ print &buffer $1 = (char (*)[256]) 0xffffcd50 gdb-peda$ print &email $2 = (char (*)[64]) 0xffffcd10
栈视图
gdb-peda$ x/100xb 0xffffcd10 0xffffcd10: 0x61 0x73 0x64 0x61 0x73 0x64 0x0a 0x35 0xffffcd18: 0x39 0x34 0x33 0x38 0x80 0xcd 0xff 0xff 0xffffcd20: 0x1b 0x71 0x55 0x56 0x2c 0xce 0xf8 0xf7 0xffffcd28: 0xb8 0xce 0xff 0xff 0xac 0x6c 0xdb 0xf7 0xffffcd30: 0x26 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xffffcd38: 0xb8 0xce 0xff 0xff 0x80 0xcd 0xff 0xff 0xffffcd40: 0x1b 0x71 0x55 0x56 0x2c 0xce 0xf8 0xf7 0xffffcd48: 0xb8 0xce 0xff 0xff 0x42 0x1b 0xdc 0xf7 0xffffcd50: 0x62 0x70 0x68 0x79 0x73 0x75 0x75 0x78 0xffffcd58: 0x73 0x72 0x6e 0x6b 0x71 0x74 0x75 0x70 0xffffcd60: 0x66 0x77 0x63 0x79 0x0a 0x00 0x00 0x00 0xffffcd68: 0x64 0xce 0xff 0xff 0x98 0xcd 0xff 0xff 0xffffcd70: 0xe4 0xcf 0xff 0xf7
内容的提问来源于stack exchange,提问作者jefrey hernandez rodriguez
相关产品推荐
相关产品推荐

