uctf-雜項題目分析

wyzsk發表於2020-08-19
作者: 路人甲 · 2014/10/28 15:04

BP 斷點


分數:100 描述: 提示 1:key 不是大家喜歡的波波老師!
提示 2:bmp+png
提示 3:CRC Link: http://pan.baidu.com/s/1o6x4FEE

Bmp 只是誘餌,給大家看看波波老師。關鍵在於 png 圖片,根據 png 格式圖片,以及提示,很明顯可以想到利用 crc 去爆破寬度和高度。可以用 c 或者 py,py 在這題爆破三個位元組還是可以的,如果位元組太多還是用 c 吧。 之所以名字叫做 BP 斷點,是因為是 bmp+png 的圖片。

參考 c 程式碼:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
//crc32.h
#ifndef _CRC32_H
#define _CRC32_H
UINT crc32( UCHAR *buf, int len);
#endif
static UINT CRC32[256];
static char init = 0;
//初始化表
static void init_table()
{
int i,j;
UINT crc;
for(i = 0;i < 256;i++)
{
crc = i;
for(j = 0;j < 8;j++)
{
if(crc & 1) 
{
crc = (crc >> 1) ^ 0xEDB88320;
}
else
{
crc = crc >> 1;
}
}
CRC32[i] = crc;
}
}
//crc32實現函式
UINT crc32( UCHAR *buf, int len)
{
UINT ret = 0xFFFFFFFF;
int i;
if( !init )
{
init_table();
init = 1;
}
for(i = 0; i < len;i++)
{
ret = CRC32[((ret & 0xFF) ^ buf[i])] ^ (ret >> 8);
}
ret = ~ret;
return ret;
}
int main()
{
char sss[17]="\x49\x48\x44\x52\x00\x00";
int a1,a2,a3,a4,a5,a6,a7,a8;
int _crc32 = 0;
for (a3=0x00;a3<=0xff;a3++)
for (a4=0x00;a4<=0xff;a4++)
for (a7=0x00;a7<=0xff;a7++)
for (a8=0x00;a8<=0xff;a8++)
{ 
sss[6]=(char)a3;
sss[7]=(char)a4;
sss[8]='\x00';
sss[9]='\x00';
sss[10]=(char)a7;
sss[11]=(char)a8;
sss[12]='\x08';sss[13]='\x06';sss[14]='\x00';sss[15]='\x00';sss[16]='\x00';
sss[17]='\x00';
_crc32 = crc32((UCHAR *)sss, 17);
if(_crc32 == 0x80BF36CC)
{
printf("%s,%x,%x,%x,%x\n", sss,a3,a4,a7,a8);
}
}
return 0;
}

最後結果:

enter image description here

參考 python 程式碼:

# -*- coding:utf-8 -*-import binascii
#注意返回的是小寫  形如:"0x1c4d1d3cL",  並且為字串。
def CalcCrc32(str):
return hex(binascii.crc32(str) & 0xFFFFFFFF)
if __name__=="__main__":
str1 = '\x49\x48\x44\x52\x00\x00\x01'
str2 = '\x00\x00'
str3 = '\x08\x06\x00\x00\x00' 
int1 = 0
int2 = 0
int3 = 0
for int1 in range(0,256):
for int2 in range(0, 256):
for int3 in range(0, 256):
m = str1   + chr(int1) + str2 + chr(int2) + chr(int3) + str3
if (CalcCrc32(m) == "0x80bf36ccL"):
print "Yeah, U Found it!"
print hex(int1)
print hex(int2)
print hex(int3)
exit()

跑幾分鐘後,結果就出來了。

enter image description here

聽聽音樂


先下載壓縮包 http://pan.baidu.com/s/1bncmvuR 解壓後發現兩個檔案Music.exe,Readme.doc. 要求利用 xp sp3 對目標程式進行溢位 既然是比賽,那麼肯定就是要有溢位點的啦 直接開啟 exe,聽到了甩蔥歌 於是不準備關掉他了, 新開一個例程,OD 載入

enter image description here

發現是 VC6 連結的 於是就果斷去找 main 函式了 不過 exe 程式居然自殺了,不能聽甩蔥歌,差評 果斷定位到了 main

enter image description here

enter image description here

寫入內容為 exe 的啟動引數 於是猜想啟動引數這個地方應該就是所謂的溢位點 於是寫了一個簡單程式,介面如下

enter image description here

最後發現 273 程式就會崩潰 於是使用 273 建立程式 OD 附加並設定 F2 斷點於 ReadFile 於多次返回後定位到

enter image description here

觀察堆疊後發現 此時已覆蓋[esp]一個位元組 Ret 後肯定會跳轉到記憶體中某一被修改的位置執行程式碼 於是構建 shellcode 記憶體收縮

FF E4 (jmp esp)

最終定位到 0x77D29353,開啟 010 editor,構建 exp.

enter image description here

enter image description here

enter image description here

接下來構造功能程式碼 之後我發現程式段裡竟然有可恥的 call eax 找了個地址比較吉利的構造了下 用阿爾法轉換了下 shellcode 最終 exp 如下

enter image description here

enter image description here

最簡單的加解密


分數:300 描述: 提示 1:DES
提示 2:凱撒

得到兩串二進位制後,轉換為 16 進位制分別為:

0x4d3259784e7a49304f444a6f4e57746f4e44597a61575a6d4d3267785a6a5a6e5a6d59344d4763344f544d354f4441784f5774724e4449796144566d4f446730L
0x5379636c30763372L

轉換為字串分別為:

M2YxNzI0ODJoNWtoNDYzaWZmM2gxZjZnZmY4MGc4OTM5ODAxOWtrNDIyaDVmODg0
Sycl0v3r

可以認為第一個字串為 DES 的密文,第二個字串為 DES 的金鑰。解密發現不對。但是根 據大小寫和數字可以猜測為 base64,解密後的字串:

3f172482h5kh463iff3h1f6gff80g89398019kk422h5f884

再用 DES 的金鑰解密,發現還是不對。根據提示“凱撒”去解碼試試。

http://crypo.in.ua/tools/eng_caesar.php

enter image description here

解幾次後發現 3a172482c5fc463daa3c1a6baa80b89398019ff422c5a884 這串是可以用DES 解密的。

enter image description here

表白牆


在輸出”tell me:”之後程式會讀入使用者輸入,但這裡使用了危險的 scanf(“%s”)而沒有任何額外 的檢查,直接輸入超長字串就可以造成 buffer overflow。

enter image description here

enter image description here

enter image description here

成功利用彈 MessageBox 的截圖如下

enter image description here

P.S:其實程式裡還有一個格式化字串漏洞,不過那個利用起來沒這個方便,所以就直接 用這個了。

找女朋友


載入到 od 中執行程式,程式發現了我們啟動了 od,並列印出了 SOD 的驅動名

enter image description here

程式 main 函式在0x401000處,在這裡用了 EnumDeviceDriversGetDeviceDriverFileNameA 函式來列舉系統中已經載入的驅動,並判斷 dbghelp.dll 路徑與系統路徑是否相同,如果不同 就認為系統中執行了 od 驅動物件的 DriverSection 儲存了一個指向_LDR_DATA_TABLE_ENTRY 指標,這個結構中有著一 個所有驅動的連結串列,透過遍歷這個連結串列就可以知道載入了哪些驅動,如果想要程式找不到一 個驅動,我們只需要從這個連結串列中把相應的驅動摘下來 以下是具體程式碼:

#include <ntddk.h>
#define INITCODE code_seg("INIT")
#define PAGECODE code_seg("PAGE")
#define PROCESS_ID_OFFSET 0x84
#define IMAGE_NAME_OFFSET 0x174
#define PROCESS_LINK_OFFSET 0x88
#define PROCESS_EXITTIME    0x78
typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID    *ServiceTableBase;
PULONG   *ServiceCounterTableBase;
ULONG     NumberOfServices;
ULONG     ParamTableBase;
}SSDT,   *PSSDT;
__declspec(dllimport) SSDT   KeServiceDescriptorTable;
//_LDR_DATA_TABLE_ENTRY 宣告
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName; 
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
ULONG TimeDateStamp;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
/////////////////////////////////////////////////////////////
void DriverUnload(IN PDRIVER_OBJECT pDriverObject);
void ShowProcess();
struct _LIST_ENTRY *tmp;
/////////////////////////////////////////////////////////////
#pragma INITCODE
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegisterPath) 
{
PLDR_DATA_TABLE_ENTRY pTableEntry = NULL;
PLIST_ENTRY pCur = NULL, pHead = NULL;
UNICODE_STRING str_Name;
ULONG EProcess,FirstEProcess;
LIST_ENTRY*  ActiveProcessLinks;
ULONG pid,dwCount=0;
PUCHAR pImage;
//PPROCESS_INFO ProcessInfo={0};
pDriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&str_Name, L"fengyue0.sys");
//從驅動物件中的 DriverSection 獲得_LDR_DATA_TABLE_ENTRY 指標
pTableEntry = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
//使頭指標和當前指標指向模組連結串列中的一個模組
pCur = pHead = pTableEntry->InLoadOrderLinks.Blink;
do 
{
//獲得模組指標
pTableEntry = (PLDR_DATA_TABLE_ENTRY)pCur;
if (pTableEntry->BaseDllName.Buffer)
{
if (RtlCompareUnicodeString(&str_Name, &(pTableEntry->BaseDllName), FALSE) == 
0)
{
//從連結串列中刪除模組
pTableEntry->InLoadOrderLinks.Blink->Flink  = 
pTableEntry->InLoadOrderLinks.Flink;
pTableEntry->InLoadOrderLinks.Flink->Blink  = 
pTableEntry->InLoadOrderLinks.Blink;
break;
}
}
pCur = pCur->Flink;
}while (pCur != pHead);
/////////////////////////////////////////////////////////////
//顯示程式
ShowProcess();
return STATUS_SUCCESS;
} 
#pragma PAGECODE
void DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
}
void ShowProcess()
{
ULONG OriFunAddr;
UNICODE_STRING str_FuncName;
PULONG ssdt_base;
RtlInitUnicodeString(&str_FuncName,L"NtQuerySystemInformation");
//獲取 ssdt 基址
ssdt_base = (PULONG) KeServiceDescriptorTable.ServiceTableBase;
//獲取 NtQuerySystemInformation 原地址
OriFunAddr =(ULONG) MmGetSystemRoutineAddress(&str_FuncName);
//判斷當前 ssdt 中地址是否被替換
if (ssdt_base[0xAD] != OriFunAddr) 
{
DbgPrint("NtQuerySystemInformation has been hooked!fix it...");
ssdt_base[0xAD] = OriFunAddr;
DbgPrint("success!");
}
}

題目中的第二個目標就是使 od 程式在 windows 自帶的工作管理員中顯示出來, fengyue0.sys 驅動會在 ssdt 中把 NtQuerySystemInformation 函式 hook 掉,所以,當 windows 的任務管理 器透過這個函式列舉程式的時候就會把 od 程式隱藏了

enter image description here

知道了隱藏的原理之後,我們的目標就轉換為了,把 NtQuerySystemInformation 的 ssdt hook 給恢復了。 在 KeServiceDescriptorTable 中可以獲得 ssdt 的基地址,再透過 NtQuerySystemInformation 在 ssdt 中的索引號就可以得到在 ssdt 中存放的它的地址,但是 ssdt 中的地址不一定是函式真 正的地址,有可能是被 hook 了的地址,所以可以再 MmGetSystemRoutineAddress 獲得函式 真正的地址,然後與 ssdt 中的對比,如果相同則說明函式沒有被 hook,反之函式被 hook, 我們的目的是恢復它的真正地址,現在既然已經有了真正的地址,就可以直接把 ssdt 中的 假地址給換掉,就恢復了 NtQuerySystemInformation 的 ssdt hook。具體程式碼在上述程式碼的 ShowProcess()函式中。

用 od 加 載 目 標 程 序 後 , 把 我 們 的 驅 動 用 DriverMonitor 加 載 並 運

enter image description here

之後在 od 中執行目標程式

enter image description here

程式顯示沒有發現 od,說明我們隱藏驅動成功了,再到 windows 工作管理員中檢視一下, ollydbg.exe 程式也出現了

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!