记录一道CTF题 wtf.sh-150

题目复现可以在攻防世界中查看

题目分成了两部分,我们需要找到两处flag(ps:这个还是第一次遇到)

0x01 第一部分flag



打开题目,是一个类似论坛一样的东西
记录一道CTF题 wtf.sh-150_第1张图片

图片一




首先是注册账号,然后登录账号,随便点了几下熟悉一下web的功能,然后通过一些简单的测试,比如sql注入,源码泄露,目录爆破等都行不通。。。。。。
最后不断尝试:在展示文章的页面 post.wtf 下发现路径穿越漏洞

从而访问源码:
记录一道CTF题 wtf.sh-150_第2张图片

图片二



习惯性的 CTRL+F去查找 flag

在这里插入图片描述

图片三

从图三可以看到伪造COOKIES即可
在源码中,我们还可以看见有users目录,我们再次进行路径穿越进../users,便可以看见admintoken

图片四

得到flag的第一部分




0x02 第二部分flag

思路:我们可以看见url解析的文件不是我们常见的php文件等,而是以wtf结尾的文件,所以源码中必有服务器如何解析此类文件的线索,我们便可以以此为线索找到flag的第二部分

先贴出找到的两段bash代码

max_page_include_depth=64  			
page_include_depth=0
function include_page {
    # include_page <pathname>       #   <和>是实体符号<和>,而-lt是小于,-gt是大于
    local pathname=$1						#   $0当前脚本的文件名;$n表示第几个参数;$#表示参数的个数;$*和$@都表示所有参数(有双引号时两者输出不同);$?表示上一个命令的退出状态,或函数的返回值(大部分命令执行成功会返回 0,失败返回 1。 );$$表示Shell进程的ID
    local cmd=""							#   local 局部变量
    [[ "${pathname:(-4)}" = '.wtf' ]];       #   pathname的最后四个字符
    local can_execute=$?;
    page_include_depth=$(($page_include_depth+1))
    if [[ $page_include_depth -lt $max_page_include_depth ]]
    then
        local line;
        while read -r line; do					#   -r表示不转义,即\n仍然是\n
            # check if we're in a script line or not ($ at the beginning implies script line)
            # also, our extension needs to be .wtf
            [[ "$" = "${line:0:1}" &amp;&amp; ${can_execute} = 0 ]];		#   ${line:0:1}表示line的第一个字符,$line{0:0:1}表示line名称的第一个字符;   &是&的实体表示
            is_script=$?;

            # execute the line.
            if [[ $is_script = 0 ]]
            then
                cmd+=$'\n'"${line#"$"}";
            else
                if [[ -n $cmd ]]    				#   -n 表示检测是否为空字符串, -z表示字符串长度是否为0
                then
                    eval "$cmd" || log "Error during execution of ${cmd}";
                    cmd=""
                fi
                echo $line
            fi
        done &lt; ${pathname}
    else
        echo "<p>Max include depth exceeded!<p>"
    fi
}





$ reply    "\${URL_PARAMS['post']}"          "\${COOKIES['USERNAME']}"        "\${POST_PARAMS['text']}"  #     reply接收的函数
function reply {
    local post_id=$1;
    local username=$2;
    local text=$3;
    local hashed=$(hash_username "${username}");

    curr_id=$(for d in posts/${post_id}/*; do basename $d; done | sort -n | tail -n 1);     #    basename表示除去后缀和前面的路径
    next_reply_id=$(awk '{print $1+1}' &lt;&lt;&lt; "${curr_id}");
    next_file=(posts/${post_id}/${next_reply_id});
    echo "${username}" &gt; "${next_file}";
    echo "RE: $(nth_line 2 &lt; "posts/${post_id}/1")" &gt;&gt; "${next_file}";
    echo "${text}" &gt;&gt; "${next_file}";

    # add post this is in reply to to posts cache
    echo "${post_id}/${next_reply_id}" &gt;&gt; "users_lookup/${hashed}/posts";
}



这是reply功能的代码,也是存在路径穿越的
我们可以使用户名为一段可执行代码,并且写入文件格式为wtf,就可以执行这段代码
先正常的回复一下,然后抓包进行修改,上传后门m.wtf,注意一点,m.wtf后面要加%09,表示制表符,否在会被当做目录去解析:

记录一道CTF题 wtf.sh-150_第3张图片

图片五


从reply可知,username也会被写进${next_file},故我们将ployload写在username中,可能会有人问,为什么不写进text中呢,因为代码一中有一句cmd+=\$'\n'"\${line#"\$"}";,后面有一个#号可以注释掉后面的内容,同时代码一中[[ "$" = "${line:0:1}" && ${can_execute} = 0 ]];要求我们必须以$开头,综上,我们的payload只有写进username中!

记录一道CTF题 wtf.sh-150_第4张图片

图片六



记录一道CTF题 wtf.sh-150_第5张图片

图片七

你可能感兴趣的:(ctf)