目标机IP:10.10.10.87
信息搜集
照常进行nmap扫描
nmap -sC -sV -A -oN 10.10.10.87.txt 10.10.10.87
发现80端口开放,扫描目录无果,进去探测一番
Get user.txt
枚举
点进网站发现没什么东西,顺手点开源码发现list.js
有一些值得注意的内容
function writeList(listNum, data){
var xhttp = new XMLHttpRequest();
xhttp.open("POST","fileWrite.php",false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send('listnum=' + listNum + '&data=' + data);
if (xhttp.readyState === 4 && xhttp.status === 200) {
return xhttp.responseText;
}else{
}
}
function deleteList(listNum){
var xhttp = new XMLHttpRequest();
xhttp.open("POST","fileDelete.php",false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send('listnum=' + listNum);
if (xhttp.readyState === 4 && xhttp.status === 200) {
listLists();
return xhttp.responseText;
}else{
}
}
function readDir(path){
var xhttp = new XMLHttpRequest();
xhttp.open("POST","dirRead.php",false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send('path=' + path);
if (xhttp.readyState === 4 && xhttp.status === 200) {
return xhttp.responseText;
}else{
}
}
function readFile(file){
var xhttp = new XMLHttpRequest();
xhttp.open("POST","fileRead.php",false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send('file=' + file);
if (xhttp.readyState === 4 && xhttp.status === 200) {
return xhttp.responseText;
}else{
}
}
这四个函数分别利用XHR访问四个不同的php文件,而且貌似进行一定程度上敏感的读写操作,十分值得注意。
那么现在就构造出了一种攻击思路:
将反弹webshell写入一个php文件->对文件进行访问获取shell
但是接下来进行枚举过程中,发现了一些问题:
首先读所有的文件,把代码读下来:
fileRead.php
<?php
if($_SERVER['REQUEST_METHOD'] === "POST"){
$fileContent['file'] = false;
header('Content-Type: application/json');
if(isset($_POST['file'])){
header('Content-Type: application/json');
$_POST['file'] = str_replace( array("../", "..\""), "", $_POST['file']); ../ .."
if(strpos($_POST['file'], "user.txt") === false){
$file = fopen("/var/www/html/" . $_POST['file'], "r");
$fileContent['file'] = fread($file,filesize($_POST['file']));
fclose();
}
}
echo json_encode($fileContent);
}
fileWrite.php
<?php
if($_SERVER['REQUEST_METHOD'] === "POST"){
header('Content-Type: application/json');
$condition['result'] = false;
if(isset($_POST['listnum'])){
if(is_numeric($_POST['listnum'])){
$myFile = "/var/www/html/.list/list" . $_POST['listnum'];
$handle = fopen($myFile, 'w');
$data = $_POST['data'];
fwrite($handle, $data);
fclose();
$condition['result'] = true;
}
}
echo json_encode($condition);
}
fileDelete.php
<?php
if($_SERVER['REQUEST_METHOD'] === "POST"){
if(isset($_POST['listnum'])){
header('Content-Type: application/json');
if(is_numeric($_POST['listnum'])){
$myFile = "/var/www/html/.list/list" . $_POST['listnum'];
unlink($myFile);
header('Content-Type: application/json');
echo '[true]';
}else{
header('Content-Type: application/json');
echo '[false]';
}
}else{
header('Content-Type: application/json');
echo '[false]';
}
}
dirRead.php
<?php
if($_SERVER['REQUEST_METHOD'] === "POST"){
if(isset($_POST['path'])){
header('Content-type: application/json');
$_POST['path'] = str_replace( array("../", "..\""), "", $_POST['path']);
echo json_encode(scandir("/var/www/html/" . $_POST['path']));
}else{
header('Content-type: application/json');
echo '[false]';
}
}
发现文件写入过程中对文件名有is_numeric
限制,文件读取和目录读取过程有preg_replace
进行目录限制。
因此没办法直接写入php文件进去,思路中断。
换个思路
preg_replace
是可以绕过的,利用重写的方式:
..././ => ../
对各种系统里的文件进行读取后,在用户目录下发现了令人感兴趣的东西:
ssh的私钥
最终通过ssh私钥登录成功获取到user.txt
Get root.txt
更换账户
从我的角度来讲这点还是挺难的
最开始还是用LinEnum来进行枚举,然而没有发现任何有用的线索
一时之间卡在这里不知道该怎么处理才好
后面突然想到之前拿到的monitor私钥在nobody账户,那么用nobody直接ssh连接monitor不知是否可行
尝试后发现可行:
发现shell受限,利用ssh强制转换shell
ssh -i .ssh/.monitor monitor@10.10.10.87 -t sh
app-dev目录下有个logmonitor应用,查看logmonitor.c可以看到能够利用logMonitor监控各种日志
/*******************************************
*
*This is an application to print out common log files
*
********************************************/
#include "logMonitor.h"
void printUsage() {
printf("Usage: %s [-aAbdDfhklmsw] [--help]\n", PROGRAMNAME);
}
int main(int argc, char** argv){
int opt = 0;
char filename[26];
{
//temporary variables for parsing
static struct option long_options[] ={
/* These options don’t set a flag.
We distinguish them by their indices. */
{"auth", no_argument, 0, 'a'},
{"alternatives", no_argument, 0, 'A'},
{"btmp", no_argument, 0, 'b'},
{"dpkg", no_argument, 0, 'd'},
{"daemon", no_argument, 0, 'D'},
{"faillog", no_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
{"kern", no_argument, 0, 'k'},
{"lastlog", no_argument, 0, 'l'},
{"messages", no_argument, 0, 'm'},
{"syslog", no_argument, 0, 's'},
{"wtmp", no_argument, 0, 'w'},
{0,0,0,0}
};
//parse the command line arguments
int option_index = 0;
while((opt = getopt_long (argc, argv, "aAbdDfhklmsw", long_options, &option_index)) != -1 ){
switch (opt) {
case 'a' :
strncpy(filename, "/var/log/auth.log", sizeof(filename));
printFile(filename);
break;
case 'A' :
strncpy(filename, "/var/log/alternatives.log", sizeof(filename));
printFile(filename);
break;
case 'b' :
strncpy(filename, "/var/log/btmp",sizeof(filename));
printFile(filename);
break;
case 'd' :
strncpy(filename, "/var/log/daemon.log",sizeof(filename));
printFile(filename);
break;
case 'D' :
strncpy(filename, "/var/log/dpkg.log",sizeof(filename));
printFile(filename);
break;
case 'f' :
strncpy(filename, "/var/log/faillog",sizeof(filename));
printFile(filename);
break;
case 'h' :
printUsage();
exit(1);
case 'k' :
strncpy(filename, "/var/log/kern.log",sizeof(filename));
printFile(filename);
break;
case 'l' :
strncpy(filename, "/var/log/lastlog",sizeof(filename));
printFile(filename);
break;
case 'm' :
strncpy(filename, "/var/log/messages",sizeof(filename));
printFile(filename);
break;
case 's' :
strncpy(filename, "/var/log/syslog",sizeof(filename));
printFile(filename);
break;
case 'w' :
strncpy(filename, "/var/log/wtmp",sizeof(filename));
printFile(filename);
break;
default:
printUsage();
exit(EXIT_FAILURE);
}
}
}
return 1;
}
但是实际运行,并没有足够权限,这一点十分奇怪。
进入目录下v0.1版本,发现0.1版本有权限,上网搜索一下是linux capabilities的问题。
用户sh有tac权限,直接读取 root.txt
完事