将Shikata ga nai带到前端

Shikata ga nai是什么 Metasploit-Framework是一个漏洞利用框架,里面有大量的漏洞库,针对shellcode一些混淆编码器可以让用户bypass一些安全软件,其中一个比较核心的编码器是Shikata Ga Nai (SGN)。 shellcode 主要是机器码,也可以看作一段汇编指令。Metasploit 在默认配置下就会对payload进行编码。虽然 Metasploit 有各种编码器,但最受欢迎的是 SGN。日语中的短语 SGN 的意思是“无能为力”,之所以这样说,是因为它在创建时传统的反病毒产品难以检测。 检测 SGN 编码的payload很困难,尤其是在严重依赖静态检测的情况下。任何基于规则的静态检测机制基本上都无法检测到用 SGN 编码的payload。而不断扫描内存的计算成本很高,因此不太可行。这使得大多数杀软依赖于行为指标和沙箱进行检测。 为什么说带到前端 首先介绍下 EgeBalci/sgn,这个项目将msf的Shikata Ga Nai编码器移植到了Golang,使得用户可以不通过msf即可享受到SGN的能力。 既然这个项目是非平台依赖的工具,那我们可以考虑将它移植到前端,这样用户只需要打开浏览器就能用了。 移植思路 首先我们可以考虑:sgn是一个golang项目,所以我们可以编译到wasm,然后暴露api给javascript来调用,这样就可以实现前端使用sgn了。 但是遇到了一些问题。 该项目并不是一个Pure Go项目,它依赖cgo,没办法编译到wasm。 但是我记得 github.com/therecipe/qt 可以编译到wasm,通过一些研究,发现它是采用了go-js-qt的桥接,qt是可以编译到wasm的,go也可以编译到wasm,然后两者之间再桥接起来。那我们可以尝试先将 github.com/keystone-engine/keystone 编译到wasm,然后将sgn项目里面调用cgo的地方全部使用 syscall/js 桥接到keystone上去,此时sgn变成了一个Pure Go项目,可以将其编译到wasm了,然后再暴露出一个接口就可以供js使用了 实现手段 cgo到桥接 sgn里面需要使用cgo是因为依赖 github.com/EgeBalci/keystone-go,看了一下这个项目,其实是keystone的包装,keystone是一个c++写的项目,所以我们可以考虑使用 emscripten 来将keystone编译到wasm,不过该项工作已经有人做了,我们在这边就不自己再花时间搭环境编译了,可以看看 alexaltea.github.io/keystone.js/ 然后我们看看sgn里面依赖cgo的地方,主要是在 pkg/sgn.go 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 package sgn import ( ... "github.com/EgeBalci/keystone-go" ) ... // Assemble assembes the given instructions // and return a byte array with a boolean value indicating wether the operation is successful or not func (encoder Encoder) Assemble(asm string) ([]byte, bool) { var mode keystone.Mode switch encoder.architecture { case 32: mode = keystone.MODE_32 case 64: mode = keystone.MODE_64 default: return nil, false } ks, err := keystone.New(keystone.ARCH_X86, mode) if err != nil { return nil, false } defer ks.Close() err = ks.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL) if err != nil { return nil, false } //log.Println(asm) bin, _, ok := ks.Assemble(asm, 0) return bin, ok } // GetAssemblySize assembes the given instructions and returns the total instruction size // if assembly fails return value is -1 func (encoder Encoder) GetAssemblySize(asm string) int { var mode keystone.Mode switch encoder.architecture { case 32: mode = keystone.MODE_32 case 64: mode = keystone.MODE_64 default: return -1 } ks, err := keystone.New(keystone.ARCH_X86, mode) if err != nil { return -1 } defer ks.Close() err = ks.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL) if err != nil { return -1 } //log.Println(asm) bin, _, ok := ks.Assemble(asm, 0) if !ok { return -1 } return len(bin) } ... 其实工作量并不大,只是需要把所有对 keystone-go 的调用换到keystone.js上即可。 ...

三月 4, 2022 · 5 分钟

ksubdomain源码阅读

前两天看了amass关于dns枚举的实现,当然关于加速dns枚举的还有ksubdomain这个项目,今天花了几分钟看了下实现 阅读基于 https://github.com/boy-hack/ksubdomain/commit/9a2f2967eb8fb5c155b22393b9241f4cd6a02dc4 分析 首先从入口点开始看 https://github.com/boy-hack/ksubdomain/blob/main/cmd/ksubdomain/enum.go#L55-L109 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 Action: func(c *cli.Context) error { if c.NumFlags() == 0 { cli.ShowCommandHelpAndExit(c, "enum", 0) } var domains []string // handle domain if c.String("domain") != "" { domains = append(domains, c.String("domain")) } if c.String("domainList") != "" { dl, err := core.LinesInFile(c.String("domainList")) if err != nil { gologger.Fatalf("读取domain文件失败:%s\n", err.Error()) } domains = append(dl, domains...) } levelDict := c.String("level-dict") var levelDomains []string if levelDict != "" { dl, err := core.LinesInFile(levelDict) if err != nil { gologger.Fatalf("读取domain文件失败:%s,请检查--level-dict参数\n", err.Error()) } levelDomains = dl } else if c.Int("level") > 2 { levelDomains = core.GetDefaultSubNextData() } opt := &options.Options{ Rate: options.Band2Rate(c.String("band")), Domain: domains, FileName: c.String("filename"), Resolvers: options.GetResolvers(c.String("resolvers")), Output: c.String("output"), Silent: c.Bool("silent"), Stdin: c.Bool("stdin"), SkipWildCard: c.Bool("skip-wild"), TimeOut: c.Int("timeout"), Retry: c.Int("retry"), Method: "enum", OnlyDomain: c.Bool("only-domain"), NotPrint: c.Bool("not-print"), Level: c.Int("level"), LevelDomains: levelDomains, } opt.Check() r, err := runner.New(opt) if err != nil { gologger.Fatalf("%s\n", err.Error()) return nil } r.RunEnumeration() r.Close() return nil }, 具体的实现细节就不关注了,可以看到入口点只是读取了一些配置,继续进入 RunEnumeration 看看 ...

二月 28, 2022 · 5 分钟

自建bitwarden备份同步到坚果云

因为bitwarden的氪金玩家才能使用双因子认证,恰好手上有个vps,搭建个bitwarden服务端来使用2fa 自建bitwarden vps比较垃圾,所以选用一个资源开销比较小的服务端比较有必要,我这里选择的是 https://github.com/mprasil/bitwarden_rs 这里采用 docker-compose 进行部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 version: '3' services: bitwarden: image: bitwardenrs/server:latest container_name: bitwarden restart: unless-stopped volumes: - ./bw-data:/data environment: - WEBSOCKET_ENABLED=true - SIGNUPS_ALLOWED=true - WEB_VAULT_ENABLED=true - ADMIN_TOKEN=xxxxxxxxxxxxxxxxxxxx ports: - "127.0.0.1:8889:80" - "127.0.0.1:8810:3012" 其中的3012是websocket通知端口 ...

十二月 10, 2021 · 2 分钟

notion实现自动发布到hugo github博客

notion是用来记录笔记的,hugo是我用来作为github博客自动构建发布的 我目前设置了一个github action是:当我的博客仓库hugo分支有push事件时,自动构建文章发布到master分支,并且发布到博客园。 但是会有这样的不便:在notion中写了一篇笔记或文章,想要发布到github静态博客上,发现需要先将文章转化成markdown,图片需要上传到图床,然后贴入markdown,然后再推送到github,等待action自动构建静态博客 既然我使用notion记录笔记,何不继续All-in-one,将notion作为我的博客发布工具。 只需要在 notion 中建立一个用于博客发布的 database,然后写完笔记后填入这个 database,再使用一些手段触发 CI 即可完成博客文章的发布 工具介绍 说干就干,写了两个工具 https://github.com/akkuman/notiontomd https://github.com/akkuman/notion_to_github_blog notiontomd 是用来notion中的某个page转化为markdown的库,当然,当前支持的block是有限的,详细信息可以查看该仓库 notion_to_github_blog则是一个github action模板,用来自动从指定格式的database中拉取需要更新发布的文章,然后利用 notiontomd 转化为markdown,然后推送到github仓库,再触发另外的github aciton进行博客静态文件构建 使用 怎么建仓怎么自动从某分支拉取推到github pages所在分支我就不展开说明了,感兴趣的可以去网上搜索相关资料,本文所关注的流程是从notion database到博客源文件 基础环境 本文所涉及到的例子环境可以前往我的博客仓库 https://github.com/akkuman/akkuman.github.io 进行查看 hugo分支用来存放博客源文件,其中有一个github action的功能是push时触发,然后自动构建推送到master分支 master分支用来存放hugo构建之后生成的站点静态文件 博客相关的图片我会推送到 https://github.com/akkuman/pic 仓库 hugo作为主分支,master设置为github pages分支(原因后面描述) workflows编写 要使用该action,首先你需要在 notion 中创建一个 database,这个 database 需要有几个字段,字段名如下: Name (title): 文章标题 Article (text): 文章链接 MDFilename (text): 创建的 markdown 文件名 Category (select): 文章分类 Tags (multi_select): 文章标签 IsPublish (checkbox): 文章是否发布 NeedUpdate (checkbox): 文章是否有更新 CreateAt (Created time): 创建时间 ...

十二月 10, 2021 · 3 分钟

识别SigFlip生成的恶意文件

最近在移植 med0x2e/SigFlip 的过程中发现了一个有意思的点,可以用来作为检测的手段 在 SigFlip 项目的 Detect/Prevent 一节中作者有提到一些检测防御手段 https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2014/2915720?redirectedfrom=MSDN Once the patch is installed and proper registry keys are set, No system restarts are required, you only need to restart the Cryptographic Services. The Applocker service will be also restarted as it depends on the cryptographic services.(@p0w3rsh3ll) Yara rule by Adrien; https://twitter.com/Int2e_/status/1330975808941330432 从 SigFlip 源码中,其实也能发现一个点 SigFlip 依赖一串特定的字节来定位shellcode的位置,详见 Native/SigLoader/SigLoader/SigLoader.cpp#L102 和 Native/SigFlip/SigFlip/SigFlip.cpp#L232 1 2 3 4 5 6 7 for (_index = 0; _index < _CertTableSize; _index++) { if (*(_pePtr + _index) == 0xfe && *(_pePtr + _index + 1) == 0xed && *(_pePtr + _index + 2) == 0xfa && *(_pePtr + _index + 3) == 0xce) { printf("[*]: Tag Found 0x%x%x%x%x", *(_pePtr + _index), *(_pePtr + _index+1), *(_pePtr + _index+2), *(_pePtr + _index+3)); _dataOffset = _index + 8; break; } } 1 2 memcpy(_encryptedData, "\xFE\xED\xFA\xCE\xFE\xED\xFA\xCE", 8); crypt((unsigned char*)_data, _dataSize, _key, _keySize, (unsigned char*)_encryptedData + 8); 也就是说我们在证书表中定位到 \xFE\xED\xFA\xCE\xFE\xED\xFA\xCE 这段特征就可以断定它疑似 SigFlip 生成的 payload 了,想要更精准一些可以结合 https://twitter.com/Int2e_/status/1330975808941330432 中提到的长度特征。 ...

十二月 10, 2021 · 2 分钟