十六进制是一种数字系统,其中使用数字 (0-9) 的组合来表示 0 到 9 的值,使用字母 (A-F) 的组合来表示 10 到 15 的值。好像很复杂,但它仍然比一切都是 1 和 0 的二进制编号要好。 几十年前,十六进制在微控制器中广泛使用。您仍然可以看到它在使用中,特别是使用用于表示各种颜色深浅的十六进制调色板。 另一方面,ASCII 代表美国信息交换标准代码,其用例与十六进制完全不同。 ASCII 是一种用于将普通语言字符转换为二进制的方法,以便计算机可以理解我们这边的指令。
总之都是老美以自己为主,下面是轻松将十六进制转换为 ASCII 的方法:
让我们考虑一下我想要转换的以下十六进制代码(问题陈述):
4c696e757868616e64626f6f6b20313233
如果我成功转换上述十六进制代码,则 ASCII 转换应如下所示:
Moneyslow.com
方法一:使用xxd命令
xxd 是一个命令行实用程序,可以从给定文本创建十六进制转储,反之亦然。
首先,我将使用 echo 命令输入十六进制字符串,并使用管道将其与 xxd 配对。
echo 4c696e757868616e64626f6f6b20313233 | xxd -r -p
这里,命令选项 -r 用于将十六进制代码转换为 ASCII,而 -p 用于打印纯文本。
sagar@linux-console:~$ echo 4c696e757868616e64626f6f6b20313233 | xxd -r -p
Moneyslow.comsagar@linux-console:~$
正如您在上面看到的,输出与终端中的提示混合在一起,因为转换后的输出没有换行符。 为了使其更具可读性,您可以在上述命令后附加 echo ''。
echo 4c696e757868616e64626f6f6b20313233 | xxd -r -p && echo ''
方法二:使用printf命令
是的,您可以使用 bash printf 命令将十六进制转换为 ASCII。在这里,我将使用 \x 选项,它将接受 1 或 2 位数字的输入,如下所示:
printf '\x4c\x69\x6e\x75\x78\x68\x61\x6e\x64\x62\x6f\x6f\x6b\x20\x31\x32\x33'
如果您在十六进制字符串末尾得到一个数字,那就没有问题,并且可以正常工作,如图所示。
方法三:使用dc命令
您可能想知道如何使用甲板计算器 (dc) 将十六进制转换为 ASCII,我将向您展示具体的操作方法。
echo "16i 4C696E757868616E64626F6F6B20313233 P" | dc
这里,16i 用于指示您正在处理十六进制基数,P 用于打印 dc 命令的输出。
通过使用上面的命令,您将得到类似的结果,如下所示:
方法四:使用Perl命令
因此,如果您的系统安装了 Perl,您可以使用此方法轻松将十六进制转换为 ASCII。只需在给定命令中将我的十六进制代码与您的十六进制代码互换即可。
echo 4c696e757868616e64626f6f6b20313233 | perl -ne 's/([0-9a-f]{2})/print chr hex $1/gie' && echo ''
您将看到如下所示的结果:
方法5:使用sed命令
此方法与上面的方法有点相似,但这里您使用 sed 使用普通表达式过滤十六进制并将其转换为 ASCII。
echo -n 4c696e757868616e64626f6f6b20313233 | sed 's/\([0-9A-F]\{2\}\)/""x\1/gI' | xargs printf && echo ''
通过使用管道,我们通过 echo 收集哈希字符串,通过将 sed 与给定表达式配对来转换它,并获得给定的输出。
方法 6:转换存储在文本文件中的十六进制字符串
因此,如果文本文件下存储有十六进制字符串,则可以使用此方法将存储的十六进制字符串转换为 ASCII。
我的十六进制字符串存储在 hex.txt 文件中,因此要转换该字符串,我必须遵循给定的命令:
cat hex.txt | xxd -r -p && echo ''
到目前为止,这是最方便的方法,因为您不必一次又一次输入十六进制字符串,最好的部分是您可以存储多个十六进制字符串并使用相同的命令转换它们。
这是我对如何使用各种方法将十六进制字符串转换为 ASCII 的看法。到目前为止,最后一个是我最喜欢的,因为与其他方法相比,它非常有效。
Linux 中有专门的十六进制编辑器,如果你愿意的话也可以尝试一下。 下面是扩展阅读:
主要参考:
https://stackoverflow.com/questions/1604765/linux-shell-scripting-hex-string-to-bytes
https://stackoverflow.com/questions/6292645/convert-binary-data-to-hex-in-shell-script
进制转换有多种工具,在linux上常见的有hexdump、od -x、xxd等
xxd
xxd比较常用,也比较好用
Usage:
xxd [options] [infile [outfile]]
or
xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]
Options:
-a toggle autoskip: A single '*' replaces nul-lines. Default off.
-b binary digit dump (incompatible with -ps,-i,-r). Default hex.
-c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).
-E show characters in EBCDIC. Default ASCII.
-e little-endian dump (incompatible with -ps,-i,-r).
-g number of octets per group in normal output. Default 2 (-e: 4).
-h print this summary.
-i output in C include file style.
-l len stop after <len> octets.
-o off add <off> to the displayed file position.
-ps output in postscript plain hexdump style.
-r reverse operation: convert (or patch) hexdump into binary.
-r -s off revert with <off> added to file positions found in hexdump.
-s [+][-]seek start at <seek> bytes abs. (or +: rel.) infile offset.
-u use upper case hex letters.
-v show version: "xxd V1.10 27oct98 by Juergen Weigert".
-p:以一个整块输出所有的hex, 不使用空格进行分割
上面的是xxd的用法,下面我们来逐步介绍!
将0x313233解释成123
root@test:/# echo 0x313233| xxd -r
123root@test:/#
将123解释成0x313233
root@test:/# echo 123|xxd -ps
3132330a
需要注意的是,我们不能直接使用xxd -r 0x313233,原因是xxd后面只能接文件!而echo 123,并用管道连接,其实就是创建了一个临时文件交给xxd来处理
局限
每行有限定字符个数,xxd -ps限定每行最多有60个16进制数
而xxd -r则至多转换16个字符
解决办法
root@test:/# echo "export FF=\"/tmp/flag\";cat $FF;echo vunerable"|xxd -p
6578706f72742046463d222f746d702f666c6167223b636174202446463b
6563686f2076756e657261626c650a
root@test:/# echo "export FF=\"/tmp/flag\";cat $FF;echo vunerable"|xxd -p|tr -d '\n'
6578706f72742046463d222f746d702f666c6167223b636174202446463b6563686f2076756e657261626c650aroot@test:/#
root@test:/# echo "export FF=\"/tmp/flag\""|xxd -p
6578706f72742046463d222f746d702f666c6167220a
root@test:/# echo 0x6578706f72742046463d222f746d702f666c616722|xxd -rp
export FF="/tmp/root@test:/# echo 0x6578706f72742046463d222f746d702f666c616722|xxd -r -p
export FF="/tmp/flag"root@test:/#
注意
对于字符串转16进制中每行60个16进制的限制,可以使用echo 123|xxd -p|tr -d '\n'
对于16进制转字符串中至多转换16个字符的限制,可以使用xxd -r -p中的r和p一定得分开
应用
root@test:/# echo "flag is here" > /tmp/flag
root@test:/# echo "\"export FF='/tmp/flag';cat $FF\""|xxd -p|tr -d '\n'
226578706f72742046463d272f746d702f666c6167273b63617420244646220aroot@test:/#
root@test:/# echo 0x226578706f72742046463d272f746d702f666c6167273b6361742024464622|xxd -r -p|xargs bash -c
flag is here
上面的应用综合利用了所学的知识,其中前两步是铺垫,最后一步才是真正的poc。需要注意的是bash -c 一定接字符串,而且该字符串需要用双引号括起来!
root@test:/# echo "flag is here" > /tmp/flag
root@test:/# echo "export FF='/tmp/flag';cat $FF"|xxd -p|tr -d '\n'
6578706f72742046463d272f746d702f666c6167273b636174202446460aroot@test:/#
root@test:/# echo 0x6578706f72742046463d272f746d702f666c6167273b63617420244646|xxd -r -p|bash -i
root@test:/# export FF='/tmp/flag';cat $FF
flag is here
root@test:/# exit
上面同样是十分完美的应用,主要特点是使用了bash -i,这相当于一个交互式的应用,管道线前面输出的内容会在这个交互中完成,完成后立刻退出!注意,管道线前面输出的内容不能用双引号括起来!
perl的妙用
cat found | sed 's/.*: "//g;s/ .*//;s/^0*//' | xargs python -c 'import sys; print "".join([bin(int(x)).lstrip("0b") for x in sys.argv[1:]])' | perl -lpe '$_=pack("B*",$_)'
最后的代码意思是前面管道输入的01字符串打包成8字节的字符串
将A\B两种不同代码替换,并输出成字符串
echo ABBBAAAABBBBBABBABBBABBB | perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0/; $_ = pack "B*", $_'