任务
- 配置Windows防火墙,开放8080端口、阻断3389端口
- 运行三段代码,对结果进行分析,第一段代码分析输出结果出现的原理,解释第二段代码和第三段代码的不同之和原因
//第一段代码
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
void here()
{
printf("hello,i am here ?\n");
exit(0);
}
void main()
{
uintptr_t buf[2];
buf[3]=(uintptr_t)here;
return;
}
//第二段代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define size 32
int main(int argc, char **argv){
char *buf1;
char *buf2;
buf1 = (char*) malloc(size);
free(buf1);
buf1=NULL;
buf2 = (char *) malloc(size);
memset(buf2, 0, size);
printf("buf2: %d\n", *buf2);
printf("==== Use After Free ===\n");
strncpy(buf1, "info", 5);
printf("buf2: %s\n\n", buf2);
free(buf2);
}
//第三段代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define size 32
int main(int argc, char **argv){
char *buf1;
char *buf2;
buf1 = (char*) malloc(size);
free(buf1);
buf2 = (char *) malloc(size);
memset(buf2, 0, size);
printf("buf2: %d\n", *buf2);
printf("==== Use After Free ===\n");
strncpy(buf1, "info", 5);
printf("buf2: %s\n\n", buf2);
free(buf2);
}
任务一 操作
打开控制面板
控制面板\系统和安全\Windows Defender 防火墙

选择高级设置

入站规则 -> 新建规则

根据以下配置修改
Allow_8080
- 规则类型:端口
- 协议和端口:TCP 特定端口:8080
- 操作:允许连接
- 作用域:全部
- 名称:Allow_8080

Block_389
- 规则类型:端口
- 协议和端口:TCP 特定端口 3389
- 操作:阻止连接
- 作用域:全部
- 名称:Block_3389

任务二
第一段代码运行结果

首先对代码进行审计,坦白来说一开始看到这串代码是有点懵的,和我们最常见的c语言代码有点区别,main函数的返回值是空,并且uintptr_t这个关键字没见过
查询资料
c语言程序运行时,是操作系统将main作为程序的“入口点”,自动启动执行main函数;
标准c规定,main的返回值必须是int(即int mian),因为程序结束时,需要通过return的值或exit()的参数向操作系统返回“执行状态”比如
return 0表示正常结束,return 非0表示异常结束);
void main()是某些编译器的 “非标准扩展”(比如老版本的 VC++),虽然可能编译通过,但移植性极差,不建议写。
uintptr_t: 是 C 语言(C99 及以后标准)中定义在 <stdint.h> 头文件里的专用无符号整数类型,存储指针的整数地址宽度和当前系统的指针完全一致(32 位系统占 4 字节,64 位系统占 8 字节)
原代码定义了一个here函数,用于输出hello,i am here ?,后退出程序,主函数定义了一个无符号整数类型的数组buf,但是出现了一个非法的操作
buf[3] = (uintptr_t)here;
出现了缓冲区溢出,导致程序输出了hello,i am here ?
后面使用pwndbg对程序的运行过程进行调试分析
pwndbg> break main
在 main() 函数入口(或第一条指令)设置断点,让程序在“出错之前”停下来
pwndbg> run
从头运行程序,这次会停在 main
pwndbg> print &buf
$1 = (uintptr_t (*)[2]) 0x7fffffffe250
buf起始地址0x7fffffffe250
pwndbg> info frame
看见了关键信息
Saved registers:
rbp at 0x7fffffffe260
rip at 0x7fffffffe268
说明返回地址(saved RIP)存在 于0x7fffffffe268
pwndbg> x/gx $rbp+8
0x7fffffffe268: 0x00007ffff7c2a1ca
得知$rbp+8 = 当前函数保存返回地址的内存位置

pwndbg> next

继续执行代码,让越界发生,再次使用命令
pwndbg> x/gx $rbp+8
0x7fffffffe268: 0x0000000000401156
pwndbg> print here
$2 = {void ()} 0x401156 <here>
此时返回地址的值于here的地址完全一样,说明数组越界刚好写到了函数返回时要用的地址,也就是说,buf[3]对应的内存地址于函数栈帧中保存返回地址的位置一致,程序执行越界写入操作后,该地址被修改为here()的地址,从而导致函数return时,程序执行流发生改变,执行here函数
第二段代码和第三段代码不同之处和原因
代码二和代码三的运行结果区别

区别在于代码二的
buf1 = NULL;
free:释放这块内存
buf1 = NULL:主动断开指针与已释放内存的关系
再次使用 buf1:等价于对 NULL 指针写数据,属于 非法内存访问,程序行为未定义
而代码三
free(buf1);
// buf1 仍然是一个“看起来正常的地址”
strncpy(buf1, "info", 5);
第二段代码在释放 buf1 后将指针置为 NULL,再次使用该指针会导致对空指针的非法访问,错误容易被发现;第三段代码释放 buf1 后未将指针清空,形成悬空指针,当后续 malloc 复用同一内存区域时,通过已释放指针写入的数据会影响新的对象,属于典型的 Use-After-Free 漏洞,错误更加隐蔽且危险。

