应用GO语言协程,高效解决ctf中MD5以及sha256爆破问题
# 应用GO语言协程,高效解决ctf中MD5以及sha256爆破问题## 例题BUUCTF:rot
### 题目
- 破解下面的密文:
- 83 89 78 84 45 86 96 45 115 121 110 116 136 132 132 132 108 128 117 118 134 110 123 111 110 127 108 112 124 122 108 118 128 108 131 114 127 134 108 116 124 124 113 108 76 76 76 76 138 23 90 81 66 71 64 69 114 65 112 64 66 63 69 61 70 114 62 66 61 62 69 67 70 63 61 110 110 112 64 68 62 70 61 112 111 112
- flag格式flag{}
### 要点
- 参考rot原理,将所有的数字 -13 后,再转ascii码
- FLAG IS flag{www_shiyanbar_com_is_very_good_????}
- MD5:38e4c352809e150186920aac37190cbc
- 爆破后四位
- 使用go语言爆破
### 答案
- flag{www_shiyanbar_com_is_very_good_@8Mu}
## 代码
- 源代码
```go
package main
import (
"crypto/md5"
"fmt"
"math"
"strings"
"time"
)
func MD5(str string) string {
data := []byte(str) //切片
has := md5.Sum(data)
md5str := fmt.Sprintf("%x", has) //将[]byte转成16进制
return md5str
}
var ans = make(chan string)
var count, sum int = 0, 0
var flag int = 0
func f(s string, com string, cnt int) {
cnt--
for i := 33; i <= 126; i++ {
temp_s := strings.Replace(s, "?", fmt.Sprintf("%c", i), 1)
if cnt == 0 {
count++
str := MD5(temp_s)
if str == com {
flag = 1
ans <- temp_s
return
}
} else {
go f(temp_s, com, cnt)
}
}
}
func main() {
s := "flag{www_shiyanbar_com_is_very_good_????}"//待爆破字符串
com := "38e4c352809e150186920aac37190cbc"//目标MD5
num := int(0)
for i := 0; i < len(s); i++ {
if s == '?' {
num++
}
}//计算未知位置数量
sum = int(math.Pow((126 - 33 + 1), float64(num)))
go f(s, com, 4)//创建协程
var sec int = 0
for flag != 1 {//flag!=1表示爆破完成
sec++
fmt.Println(count, "/", sum, ":", flag)
time.Sleep(1 * time.Second)
}
fmt.Println(count, "/", sum, ":", <-ans)
fmt.Print("Time:", sec)
}
```
- 运行结果如下:
```
Starting: D:\lenovo\VSCode\Go\bin\dlv.exe dap --listen=127.0.0.1:8737 from D:\lenovo\VSCode\CTF\buuctf_crypto\5.8\rot
DAP server listening at: 127.0.0.1:8737
Type 'dlv help' for list of commands.
0 / 78074896 : 0
9089074 / 78074896 : 0
18553168 / 78074896 : 0
25049890 / 78074896 : 0
32998255 / 78074896 : 0
40769957 / 78074896 : 0
48668620 / 78074896 : flag{www_shiyanbar_com_is_very_good_@8Mu}
Time:6
Process 25280 has exited with status 0
Detaching
```
- 代码中包含一个不太严谨的计时器以及爆破进度条,仅供参考。
## 延伸
- 类似的对于sha256爆破也可以使用几乎相同的代码
- 仅需修改计算模块:
```go
import (
"crypto/sha256"//添加
"encoding/hex"//添加
"fmt"
"math"
"strings"
"time"
)
func sha(str string) string {
h := sha256.New()
h.Write([]byte(str))
a := h.Sum(nil)
hashCode2 := hex.EncodeToString(a[:]) //将数组转换成切片,转换成16进制,返回字符串
return hashCode2
}
```
- f函数中将计算过程调用的函数从MD5换为sha
- 替换为str := sha(temp_s)
- 例如计算:
- s := "????" + "teilcm0NyiScbzKQ"
- com := "71cee1525a232a1b6e828d85fa14d089d323b6af6a64d5454a12192382258aab"
- 结果为:
```
Starting: D:\lenovo\VSCode\Go\bin\dlv.exe dap --listen=127.0.0.1:9012 from D:\lenovo\VSCode\CTF\ciscn\1
DAP server listening at: 127.0.0.1:9012
Type 'dlv help' for list of commands.
0 / 78074896 : 0
5764073 / 78074896 : 0
20661477 / 78074896 : 0
29663447 / 78074896 : 0
38204353 / 78074896 : 0
45519550 / 78074896 : 0
52308375 / 78074896 : 0
59639937 / 78074896 : QVNtteilcm0NyiScbzKQ
Time:7 115
``` 不明白对于这种计算瓶颈的任务,楼主使用协程的目的和意义是什么 高维可破 发表于 2023-7-28 18:01
不明白对于这种计算瓶颈的任务,楼主使用协程的目的和意义是什么
本来写的是python多线程,不太会写Python的多线程,不太稳定。
用go的协程变相实现多线程,加快枚举爆破速度。 本帖最后由 高维可破 于 2023-7-28 21:57 编辑
Twilightl 发表于 2023-7-28 21:42
本来写的是python多线程,不太会写Python的多线程,不太稳定。
用go的协程变相实现多线程,加快枚举爆破 ...
协程提高的是并发量
对计算瓶颈场景下起不了多大作用
起作用的应该是提高并行计算量
另外go的协程会自动启动多线程? 还是只在一个线程上模拟? 高维可破 发表于 2023-7-28 21:56
协程提高的是并发量
对计算瓶颈场景下起不了多大作用
起作用的应该是提高并行计算量
计算过程中对于爆破过程做了优化,对比单线程时直接递归暴力,多线程下可以并行。
比如有两位未知,每一位有10种情况,开始程序就会创建10个协程,直接完成第一位的枚举,然后同时开始下一位的枚举,肯定加快了爆破效率 高维可破 发表于 2023-7-28 21:56
协程提高的是并发量
对计算瓶颈场景下起不了多大作用
起作用的应该是提高并行计算量
GO的协程我记得是在一个线程上模拟的,但感觉实际用起来应该是自动多线程了,你可以再查查手册看看。 本帖最后由 高维可破 于 2023-7-29 06:57 编辑
Twilightl 发表于 2023-7-28 23:34
计算过程中对于爆破过程做了优化,对比单线程时直接递归暴力,多线程下可以并行。
比如有两位未知,每一 ...
这个是否高效取决于是否在多核上并行运算。
如果只是单线程模拟 这种情况下的协程实际上就是单线程暴力枚举 ,
没有差别 甚至还多出了维护协程的开销
这个也就是我之前提问的原因所在 高维可破 发表于 2023-7-29 06:54
这个是否高效取决于是否在多核上并行运算。
如果只是单线程模拟 这种情况下的协程实际上就是单线程暴力 ...
我查到一下两段:
协程可以理解为轻量级线程,一个线程可以拥有多个协程,与线程相比,协程不受操作系统调度,协程调度器按照调度策略把协程调度到线程中执行,协程调度器由应用程序的runtime包提供,用户使用go关键字即可创建协程,这也就是GO在语言层面直接支持协程的含义。
由于协程运行在用户态,能够大大减少上下文切换带来的开销,并且协程调度器把可运行的协程逐个调度到线程中执行,同时及时把阻塞的协程调度出线程,从而有效的避免了线程的频繁切换,达到了使用少量的线程实现高并发的效果,但是对于一个线程来说每一时刻只能运行一个协程。
我理解的是运行过程中,可以并行的协程会被放到多个线程中执行。所以协程也是并行运算的。
实际使用中,运算用时比单纯递归爆破快很多。
然后运行时简单的观察win11任务管理器,cpu负载会升到80%以上,线程数会多几百个。
直接递归的话占用小很多,用时也很长。
页:
[1]