REVERSE-PRACTICE-BUUCTF-21
REVERSE-PRACTICE-BUUCTF-21
- [SCTF2019]babyre
- [MRCTF2020]EasyCpp
- [GUET-CTF2019]encrypt
- [QCTF2018]Xman-babymips
[SCTF2019]babyre
elf文件,無殼,用ida分析
在start函數中看到main函數的字樣,但是左側函數窗沒有找到main函數
原因是main函數中加了花指令,導致ida不能正確地分析main函數
main函數中有三處類似這樣的花指令,把jb,jnb,loope三條指令都nop掉,創建函數,F5反編譯
main函數中要求輸入三個password,三個pwd都正確才能得到flag
先看第一個password的部分,是個走迷宮的邏輯
v28~v44是迷宮的map,長度為125,起點為’s’
往下走,switch case語句是由輸入pwd1的字符決定方向,w-上,s-下,d-右,a-左,x-下一塊,y-上一塊,由此可以知道,長度為125的map,每25分為一個塊,每個塊又是5x5排列,路線只能走’.’,終點為’#’,要求最短的路線
將長度為125的map按照每25一塊,每塊5x5排列的方式,按w-上,s-下,d-右,a-左,x-下一塊,y-上一塊的規定,得到最短的路線為sxss,驗證正確
往下走,看第二個password的部分
pwd2和v17作為參數傳入loc_C22邏輯段的函數,過程中v17被賦值,函數返回后v17和v8比較,已知v8是字符串"sctf_9102"
loc_C22邏輯段的代碼也被插入了花指令,jb和jnb直接nop掉,“in"指令的第一個字節改成0x90
下面未被識別成代碼的數據按d轉成一個一個字節的形式,把前兩個值為0的字節改成0x90
創建函數,F5反編譯
進入sub_C22函數,來到給v17賦值的部分
0x3f的二進制為0b00111111,v7又被v7<<6賦值,v9等于4時才會進入if語句給v17賦值,由6x4=8x3,猜測是base64的反編碼過程,反編碼的結果為v8的字符串"sctf_9102”,于是pwd2為v8的base64編碼,即為"c2N0Zl85MTAy",驗證正確
往下走,看第三個password的部分
pwd3進入sub_FFA函數進行驗證,返回1驗證成功
進入sub_FFA函數,將輸入的pwd3按大端序規則,16個byte轉成4個int,do循環體中的sub_143B進行變換和賦值,最后四次循環賦值給v44~v47,v44到v47的4個int按大端序規則,轉成16個byte,與v8比較驗證
signed __int64 __fastcall sub_FFA(char *pwd3) {int v1; // ST24_4int v2; // ST28_4int v3; // ST2C_4signed int v5; // [rsp+18h] [rbp-158h]signed int i; // [rsp+18h] [rbp-158h]int v7; // [rsp+1Ch] [rbp-154h]int v8; // [rsp+30h] [rbp-140h]int v9; // [rsp+34h] [rbp-13Ch]int v10; // [rsp+38h] [rbp-138h]int v11; // [rsp+3Ch] [rbp-134h]int v12; // [rsp+40h] [rbp-130h]int v13; // [rsp+44h] [rbp-12Ch]int v14; // [rsp+48h] [rbp-128h]int v15; // [rsp+4Ch] [rbp-124h]int v16; // [rsp+50h] [rbp-120h]int v17; // [rsp+54h] [rbp-11Ch]int v18; // [rsp+58h] [rbp-118h]int v19; // [rsp+5Ch] [rbp-114h]int v20; // [rsp+60h] [rbp-110h]int v21; // [rsp+64h] [rbp-10Ch]int v22; // [rsp+68h] [rbp-108h]int v23; // [rsp+6Ch] [rbp-104h]unsigned int v24; // [rsp+70h] [rbp-100h]int v25; // [rsp+74h] [rbp-FCh]int v26; // [rsp+78h] [rbp-F8h]int v27; // [rsp+7Ch] [rbp-F4h]unsigned int v28; // [rsp+80h] [rbp-F0h]int v29; // [rsp+84h] [rbp-ECh]int v30; // [rsp+88h] [rbp-E8h]int v31; // [rsp+8Ch] [rbp-E4h]unsigned int v32; // [rsp+90h] [rbp-E0h]int v33; // [rsp+94h] [rbp-DCh]int v34; // [rsp+98h] [rbp-D8h]int v35; // [rsp+9Ch] [rbp-D4h]unsigned int v36; // [rsp+A0h] [rbp-D0h]int v37; // [rsp+A4h] [rbp-CCh]int v38; // [rsp+A8h] [rbp-C8h]int v39; // [rsp+ACh] [rbp-C4h]int v40; // [rsp+B0h] [rbp-C0h]int v41; // [rsp+B4h] [rbp-BCh]int v42; // [rsp+B8h] [rbp-B8h]int v43; // [rsp+BCh] [rbp-B4h]unsigned int v44; // [rsp+118h] [rbp-58h]unsigned int v45; // [rsp+11Ch] [rbp-54h]unsigned int v46; // [rsp+120h] [rbp-50h]unsigned int v47; // [rsp+124h] [rbp-4Ch]unsigned __int64 v48; // [rsp+168h] [rbp-8h]v48 = __readfsqword(0x28u);v8 = 0xBE;v9 = 4;v10 = 6;v11 = 0x80;v12 = 0xC5;v13 = 0xAF;v14 = 0x76;v15 = 0x47;v16 = 0x9F;v17 = 0xCC;v18 = 0x40;v19 = 0x1F;v20 = 0xD8;v21 = 0xBF;v22 = 0x92;v23 = 0xEF;v1 = (pwd3[6] << 8) | (pwd3[5] << 16) | (pwd3[4] << 24) | pwd3[7];// 大端序v2 = (pwd3[10] << 8) | (pwd3[9] << 16) | (pwd3[8] << 24) | pwd3[11];v3 = (pwd3[14] << 8) | (pwd3[13] << 16) | (pwd3[12] << 24) | pwd3[15];v7 = 0;v5 = 4;v40 = sub_78A((pwd3[2] << 8) | (pwd3[1] << 16) | (*pwd3 << 24) | (unsigned int)pwd3[3]);// 大端序v41 = sub_78A(v1);v42 = sub_78A(v2);v43 = sub_78A(v3); // v40~v43被pwd3賦值,按大端序規則,16個byte轉成4個intdo{*(&v40 + v5) = sub_143B(*(&v40 + v7), *(&v40 + v7 + 1), *(&v40 + v7 + 2), *(&v40 + v7 + 3));// 變換++v7;++v5;}while ( v5 <= 29 );v24 = v44 >> 24; // do循環體填充v43~v44之間的地址,v44~v47是最后四次循環被賦值v25 = BYTE2(v44);v26 = BYTE1(v44);v27 = (unsigned __int8)v44;v28 = v45 >> 24;v29 = BYTE2(v45);v30 = BYTE1(v45);v31 = (unsigned __int8)v45;v32 = v46 >> 24;v33 = BYTE2(v46);v34 = BYTE1(v46);v35 = (unsigned __int8)v46;v36 = v47 >> 24;v37 = BYTE2(v47);v38 = BYTE1(v47);v39 = (unsigned __int8)v47;for ( i = 0; i <= 15; ++i ){if ( *(&v24 + i) != *(&v8 + i) ) // v44~v47的4個int分成16個byte,與v8比較return 0xFFFFFFFFLL;}return 1LL; }sub_143B函數,異或運算
__int64 __fastcall sub_143B(int a1, int a2, int a3, unsigned int a4) {return a1 ^ (unsigned int)sub_1464(a2 ^ a3 ^ a4); }sub_1464函數,主要也是異或運算
__int64 __fastcall sub_1464(unsigned int a1) {int v1; // ST18_4int v3[290]; // [rsp+20h] [rbp-490h]unsigned __int64 v4; // [rsp+4A8h] [rbp-8h]v4 = __readfsqword(0x28u);qmemcpy(v3, &off_1940, 1152uLL);v1 = (v3[BYTE2(a1)] << 16) | v3[(unsigned __int8)a1] | (v3[BYTE1(a1)] << 8) | (v3[a1 >> 24] << 24);return __ROL4__(v1, 12) ^ (unsigned int)(__ROL4__(v1, 8) ^ __ROR4__(v1, 2)) ^ __ROR4__(v1, 6); }于是do循環體中的變換賦值主要是異或運算,直接可逆,sub_1464函數的代碼直接用,寫腳本即可解出pwd3
#include <stdio.h> #include "ida_defs.h" unsigned int off_1940[288] = {0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7,0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05,0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3,0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95,0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6,0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA,0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B,0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2,0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 0x87,0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E,0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5,0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55,0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60,0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F,0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F,0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8,0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD,0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0,0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E,0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20,0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48,0xC6, 0xBA, 0xB1, 0xA3, 0x50, 0x33, 0xAA, 0x56,0x97, 0x91, 0x7D, 0x67, 0xDC, 0x22, 0x70, 0xB2,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };unsigned int sub_1464(unsigned int a1) {int v1;v1 = (off_1940[BYTE2(a1)] << 16) | off_1940[(unsigned __int8)a1] | (off_1940[BYTE1(a1)] << 8) | (off_1940[a1 >> 24] << 24);return __ROL4__(v1, 12) ^ (unsigned int)(__ROL4__(v1, 8) ^ __ROR4__(v1, 2)) ^ __ROR4__(v1, 6); }int main() {unsigned int v40[30] = { 0 };v40[26] = 0xBE040680;v40[27] = 0xC5AF7647;v40[28] = 0x9FCC401F;v40[29] = 0xD8BF92EF;int i;for (i = 25; i >= 0; i--)v40[i] = sub_1464(v40[i + 1] ^ v40[i + 2] ^ v40[i + 3]) ^ v40[i + 4];for (i = 0; i < 4; i++)printf("%c%c%c%c", ((char*)&v40[i])[0], ((char*)&v40[i])[1], ((char*)&v40[i])[2], ((char*)&v40[i])[3]);return 0; //fl4g_is_s0_ug1y! }將三個password輸入,得到flag
但是提交失敗,看里別的師傅的wp,第一個password走迷宮出錯了
正確的pwd1為ddwwxxssxaxwwaasasyywwdd
于是flag為sctf{ddwwxxssxaxwwaasasyywwdd-c2N0Zl85MTAy(fl4g_is_s0_ug1y!)}
[MRCTF2020]EasyCpp
elf文件,無殼,ida分析
main函數,讀取輸入,輸入賦到v21,利用迭代器將v21從頭到尾全部異或1
異或1后的輸入進入depart函數,將輸入分解成其因子,各因子間用空格分隔,結果放到v15,v15進入func進行替換,數字變字符,空格變等號,替換后的結果進入check與已知比較
depart函數
寫逆運算腳本即可得到正確的輸入
將數字串取32位大寫md5散列即可提交成功
[GUET-CTF2019]encrypt
elf文件,無殼,ida分析
main函數,邏輯清晰,讀取輸入,對輸入進行RC4加密,再進行很像base64的變換,只是沒有從表中取值,變換后的輸入與已知的數據比較,驗證輸入
由最后要比較的數據,逆很像base64的變換,得到輸入經RC4加密后的密文
res="Z`TzzTrD|fQP[_VVL|yneURyUmFklVJgLasJroZpHRxIUlH\\vZE=" data=[] for i in range(len(res)-1):data.append(ord(res[i])-61) data.append(ord('=')) cipher=[] for i in range(0,len(data),4):tmp=bin(data[i]).replace('0b','').zfill(6)+bin(data[i+1]).replace('0b','').zfill(6)+bin(data[i+2]).replace('0b','').zfill(6)+bin(data[i+3]).replace('0b','').zfill(6)a=int('0b'+tmp[0:8],2)b=int('0b'+tmp[8:16],2)c=int('0b'+tmp[16:24],2)cipher.append(a)cipher.append(b)cipher.append(c) print(cipher) #[118, 53, 253, 245, 125, 71, 254, 149, 19, 122, 38, 89, 63, 255, 49, 161, 133, 124, 99, 2, 110, 189, 147, 106, 62, 77, 141, 215, 39, 115, 45, 94, 204, 98, 242, 223, 229, 210, 61]由已知的密鑰(v10~v17的8個字節)和密文cipher,解密RC4,即可得到flag
#include<stdio.h> void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k) //初始化函數 {int i = 0, j = 0;char k[256] = { 0 };unsigned char tmp = 0;for (i = 0; i < 256; i++) {s[i] = i;k[i] = key[i % Len_k];}for (i = 0; i < 256; i++) {j = (j + s[i] + k[i]) % 256;tmp = s[i];s[i] = s[j]; s[j] = tmp;} }/* RC4加解密函數 unsigned char* Data 加解密的數據 unsigned long Len_D 加解密數據的長度 unsigned char* key 密鑰 unsigned long Len_k 密鑰長度 */ void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密 {unsigned char s[256];rc4_init(s, key, Len_k);int i = 0, j = 0, t = 0;unsigned long k = 0;unsigned char tmp;for (k = 0; k < Len_D; k++) {i = (i + 1) % 256;j = (j + s[i]) % 256;tmp = s[i];s[i] = s[j]; s[j] = tmp;t = (s[i] + s[j]) % 256;Data[k] = Data[k] ^ s[t];} } void main() {//密鑰unsigned char key[] = {16,32,48,48,32,32,16,64};//密鑰長度 unsigned long key_len = sizeof(key);//密文unsigned char data[] = { 118, 53, 253, 245, 125, 71, 254, 149, 19, 122, 38, 89, 63, 255, 49, 161, 133, 124, 99, 2, 110, 189, 147, 106, 62, 77, 141, 215, 39, 115, 45, 94, 204, 98, 242, 223, 229, 210, 61 };//解密rc4_crypt(data, sizeof(data), key, key_len);for (int i = 0; i < sizeof(data); i++){printf("%c", data[i]);} } //flag{e10adc3949ba59abbe56e057f20f883e}[QCTF2018]Xman-babymips
mips文件,無殼,用ida7.5打開(其他版本的ida可能不能反編譯mips)
main函數,讀取輸入,長度為32,先進行input[i]^=32-i的變換,變換后的input的前5個字符與"Q|j{g"比較,相同時進入sub_4007F0函數,對后27個字符再進行變換
sub_4007F0函數,不考慮前5個字符,下標從5開始,分奇偶數對輸入進行移位變換,變換后與已知數據比較
寫逆腳本即可得到flag
總結
以上是生活随笔為你收集整理的REVERSE-PRACTICE-BUUCTF-21的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 招行现金分期提前还款 招行现金分期可以提
- 下一篇: PWN-PRACTICE-BUUCTF-