PHP 探测任意网站密码明文/加密手段办法: md5('240610708') == md5('QNKCDZO') - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
est
V2EX    PHP

PHP 探测任意网站密码明文/加密手段办法: md5('240610708') == md5('QNKCDZO')

  •  5
     
  •   est 2015-05-04 15:51:31 +08:00 27686 次点击
    这是一个创建于 3818 天前的主题,其中的信息可能已经有所发展或是发生改变。
    var_dump(md5('240610708') == md5('QNKCDZO'));
    var_dump(md5('aabg7XSs') == md5(aabC9RqS'));
    var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
    var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
    var_dump('0010e2' == '1e3');
    var_dump('0x1234Ab' == '1193131');
    var_dump('0xABCdef' == ' 0xABCdef');

    感觉这个不科学啊

    https://news.ycombinator.com/item?id=9484757
    79 条回复    2015-12-08 15:16:31 +08:00
    ywisax
        1
    ywisax  
       2015-05-04 15:59:28 +08:00   2
    观察下最终的hash就明白了,都是0eXXXXXXXX 。
    再加上php是弱语言,会自动判断数据类型。
    零=零,明白了吧?
    anyforever
        2
    anyforever  
       2015-05-04 16:01:40 +08:00
    md5('240610708'); // 0e462097431906509019562988736854
    md5('QNKCDZO'); // 0e830400451993494058024219903391

    怎么可能这么容易碰撞
    anyforever
        3
    anyforever  
       2015-05-04 16:03:25 +08:00
    var_dump(md5('240610708') === md5('QNKCDZO'));
    ywisax
        4
    ywisax  
       2015-05-04 16:04:00 +08:00   2
    准确点说,是“==”对比的时候会进行数据转换,0eXXXXXXXXXX 转成0了。
    了解php的“==”和“===“就更加清晰了。
    yangff
        5
    yangff  
       2015-05-04 16:08:28 +08:00   3
    aliang032
        6
    aliang032  
       2015-05-04 16:12:56 +08:00   1
    找了下手册说明贴给大家:

    如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行

    http://php.net/manual/zh/language.operators.comparison.php
    est
        7
    est  
    OP
       2015-05-04 16:21:17 +08:00
    @ywisax
    @yangff

    脑洞够大!
    xifangczy
        8
    xifangczy  
       2015-05-04 16:34:44 +08:00
    卧槽 这脑洞。。太赞了
    raincious
        9
    raincious  
       2015-05-04 16:36:13 +08:00
    这是个坑没错,所以密码比较的时候需要用 ===。但,怎么用它来:

    > PHP 探测任意网站密码明文/加密手段办法

    ?不解。
    est
        10
    est  
    OP
       2015-05-04 16:47:41 +08:00   16
    @raincious 把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。


    同理,密码设置为 240610708,换密码 QNKCDZO 登录能成功,那么密码没加盐直接md5保存的。
    cat9life
        11
    cat9life  
       2015-05-04 17:00:31 +08:00
    长见识啊...
    avtester
        12
    avtester  
       2015-05-04 17:03:44 +08:00
    知道了又能如何?
    bingu
        13
    bingu  
       2015-05-04 17:04:55 +08:00
    呃,这个略迪奥
    xierch
        14
    xierch  
       2015-05-04 17:06:20 +08:00
    PHP 的大坑哈哈哈
    tabris17
        15
    tabris17  
       2015-05-04 17:07:41 +08:00
    能强等的地方我都用强等的
    NeoAtlantis
        16
    NeoAtlantis  
       2015-05-04 17:09:45 +08:00 via Android   1
    散列不叫加密!
    要不谁给我解密看看?XD
    wy315700
        17
    wy315700  
       2015-05-04 17:12:46 +08:00
    收藏了 ,好牛逼的攻击
    raincious
        18
    raincious  
       2015-05-04 18:22:46 +08:00
    @est

    恍然大悟,感谢!
    Citrus
        19
    Citrus  
       2015-05-04 18:31:35 +08:00 via iPhone
    第一次见到如此能唬人的标题党。。。看标题以为楼主完全攻破了 MD5 可以批量找碰撞了。。。
    rwalle
        20
    rwalle  
       2015-05-04 18:46:33 +08:00
    PHP中的==是挺坑的
    但是PHP中还有很多同样大的坑。。。
    codejay
        21
    codejay  
       2015-05-04 18:47:30 +08:00
    这不是两个字符串比较吗 为什么要转换成数字
    wy315700
        22
    wy315700  
       2015-05-04 18:51:51 +08:00
    @codejay php会转义一部分字符串到数字的。。。
    gDD
        23
    gDD  
       2015-05-04 18:54:27 +08:00 via iPhone
    @est @raincious 不一定,我所有判断都用 === 或者 !== 判断,只有不专业选手用 == 判断才会出你说的脑洞…
    gDD
        24
    gDD  
       2015-05-04 18:55:57 +08:00 via iPhone
    还有判断密码,secret 等要用 hash_equals(),直接用 === 会出 Timing Attack 漏洞的。
    lincanbin
        25
    lincanbin  
       2015-05-04 19:05:45 +08:00
    @gDD hash_equals版本要求太高了,只能自己项目用着玩,开源项目用不了。
    gDD
        26
    gDD  
       2015-05-04 19:13:34 +08:00 via iPhone
    @lincanbin 开源项目我觉得反而更容易解决,composer 一个 symfony security core 就好,里面有 hash_equals 的 shim,反而是公司内没用 composer 管理的的私有项目比较难维护。
    noanti
        27
    noanti  
       2015-05-04 19:50:33 +08:00
    这是php的feature?
    php还真是最好的语言。。。
    tSQghkfhTtQt9mtd
        28
    tSQghkfhTtQt9mtd  
       2015-05-04 19:56:19 +08:00 via Android
    password_hash() 路过......
    icanfork
        29
    icanfork  
       2015-05-04 20:07:33 +08:00 via Android
    md5,加盐,md5,取前30位
    xiaozi
        30
    xiaozi  
       2015-05-04 20:09:45 +08:00
    这完全是没有 ===,如果是 ===, 根本就没办法检测吧。
    lyf362345
        31
    lyf362345  
       2015-05-04 20:25:34 +08:00
    @yangff 好大
    lyf362345
        32
    lyf362345  
       2015-05-04 20:32:43 +08:00
    @est 这个有意思
    est
        33
    est  
    OP
       2015-05-04 20:46:50 +08:00
    @gDD wordpress专业不?
    invite
        34
    invite  
       2015-05-04 22:02:18 +08:00
    从另一方面印证了:PHP 是全宇宙最牛逼的语言。
    barbery
        35
    barbery  
       2015-05-04 22:11:55 +08:00
    官方都建议直接用password_hash加密,用md5还不加salt,我就真的没话说了
    Jaylee
        36
    Jaylee  
       2015-05-04 22:16:21 +08:00
    搞不懂这个贴子为啥到处都是,做PHP的人基础都这么差? 都没看过手册?
    est
        37
    est  
    OP
       2015-05-04 22:56:45 +08:00
    @Jaylee 这个bug是最近wordpress爆出来的。。你是想说wordpress的人基础差么。。。
    Kabie
        38
    Kabie  
       2015-05-04 23:04:14 +08:00
    @est 基础好的人用PHP吗。。。
    kofj
        40
    kofj  
       2015-05-04 23:48:54 +08:00
    楼主的语法有问题.fix:探测任意php网站密码明文/加密手段办法
    Jaylee
        41
    Jaylee  
       2015-05-04 23:57:03 +08:00
    @est 不管是不是wordpress基础差,至少我能看出是PHP弱类型导致的。再说,这也不过是一个小bug而已,有必要往这里发?
    bdnet
        42
    bdnet  
       2015-05-04 23:58:56 +08:00
    除了用 === ,还可以用 strcmp ,返回 0 是相等
    bdnet
        43
    bdnet  
       2015-05-05 00:02:34 +08:00
    PHP是世界上最好的语言

    2333
    iyaozhen
        44
    iyaozhen  
       2015-05-05 01:22:19 +08:00   1
    @est 不是一般都数据库查询比较吗?SELECT count(*) FROM user WHERE username = '$usename' AND password = '$password';
    czb
        45
    czb  
       2015-05-05 04:42:23 +08:00 via Android
    evlos
        46
    evlos  
       2015-05-05 05:40:38 +08:00
    看到 #44 我好像突然知道为什么很多网站连密码都有格式限制了。。。
    rwalle
        47
    rwalle  
       2015-05-05 06:02:30 +08:00
    44楼。。。
    djyde
        48
    djyde  
       2015-05-05 08:04:17 +08:00
    作为一个 Javascripter,我表示用 === 是个良好的习惯
    lincanbin
        49
    lincanbin  
       2015-05-05 08:13:01 +08:00 via Android
    @iyaozhen 你这样写要注入了……
    kfll
        50
    kfll  
       2015-05-05 08:53:21 +08:00 via iPhone
    @iyaozhen 如果要告诉用户用户名不存在还是密码错误的话,
    hahastudio
        51
    hahastudio  
       2015-05-05 10:04:25 +08:00
    太可怕
    HN 的这条回复很能说明问题:
    They're comparing two things of the same type: two strings!
    chaucerling
        52
    chaucerling  
       2015-05-05 10:10:43 +08:00
    语言设计上的坑太多233
    fashioncj
        53
    fashioncj  
       2015-05-05 10:35:08 +08:00
    作为一个渗透学习者最喜欢44楼这样的程序猿了~
    66beta
        54
    66beta  
       2015-05-05 10:57:28 +08:00
    44楼处世未深,你们别欺负他
    tuoxie007
        55
    tuoxie007  
       2015-05-05 11:04:38 +08:00
    PHP是世界上最好的语言 +1
    yxzblue
        56
    yxzblue  
       2015-05-05 11:05:56 +08:00
    看来dz生成一个随机的salt值进行二次加密再保存,果然是要好一些啊。
    gDD
        57
    gDD  
       2015-05-05 11:22:23 +08:00
    @est 一开始我以为 (string) == (string) 是绝对以字符串形式做对比的,但是查了 PHP Manual 之后,发现If you compare a number with a string **or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically**. 确实也业余了一把,简直宇宙最大坑!xD -- http://php.net/manual/en/language.operators.comparison.php

    说几个相关项目:

    Laravel 4 的时候也爆出过一个更直接的漏洞,直接传入 'true' 就足够。 -- http://barryvdh.nl/laravel/2015/02/21/csrf-protection-in-laravel-explained/

    jQuery 的规范里规定了 Strict equality checks (===) must be used in favor of abstract equality checks (==). The only exception is when checking for undefined and null by way of null. -- https://contribute.jquery.org/style-guide/js/

    而 PHP 的 == 比 Javascript 的 == 更散漫,本身 PHP 里 null 和 false 就是要用 === 来判断的,这回 OP 的问题一受到重视,连 (string) 也必须强制 === 了。
    zhengkai
        58
    zhengkai  
       2015-05-05 12:06:51 +08:00   2
    上午研究了一下这个问题,根本原因是科学计数法这个 feature

    php > var_dump('0e1' == '0e2');
    bool(true)

    “数字 e 数字”格式的字符串有时被作为数字,有时被作为字符串



    php > echo intval('1e10');
    1
    php > echo '1e10' + 0;
    10000000000

    但是混蛋就混蛋在 (string) == (string) 时也会做这个转换,这就没法搞了(更何况都是字符串还要这么转换,也会降低性能)

    比方说 switch((string)$s) { 的时候就完全没法规避这个问题

    前同事从源码里看到这个判断的函数叫 zendi_smart_strcmp

    下一个补丁应该能修正这个问题(纯字符串比较不做转换),但是这个问题感觉还是挺伤的
    bravecarrot
        59
    bravecarrot  
       2015-05-05 12:45:48 +08:00 via iPad
    @est 脑洞大,蛮有道理
    iyaozhen
        60
    iyaozhen  
       2015-05-05 13:26:13 +08:00
    @evlos
    @rwalle
    @lincanbin
    @66beta
    @fashioncj
    汗。。。求说清楚呀,我感觉我老板要开除我了。
    肯定不直接拼sql,我也知道一点 sql 注入,但是一直浮于表面,求指点。
    $password 拼 sql 之前肯定会 $password = sha1/md5($password+$salt) 。
    账号($username)的话一般有限制只能数字或者字母,然后自我安慰 mysql_real_escape_string() 一下(老感觉这个不靠谱)。
    当然这样就只能提示账号或密码错误(不匹配)。

    要看账号是不是存在,SELECT count(*) FROM user WHERE username = '$username'; 这样?看来账号也不能明文存。是不是可以可逆加密或者简单的 base64 编码一下。
    Daniel65536
        61
    Daniel65536  
       2015-05-05 13:33:00 +08:00 via iPad
    @iyaozhen username= " ' or 1=1 or ' "
    iyaozhen
        62
    iyaozhen  
       2015-05-05 13:41:50 +08:00
    @Daniel65536 这个我知道,一般账号也只允许字母或数字。而且分号会被mysql_real_escape_string过滤掉吧。

    我的本意是若网站使用 SELECT count(*) FROM user WHERE username = '$username' AND password = '$password'; 这种方式的话“把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。”就不能说明网站是明文保存呀。
    lincanbin
        63
    lincanbin  
       2015-05-05 13:42:33 +08:00
    http://www.94cb.com/t/2516

    昨晚睡觉前写了一篇来解释PHP中隐式转换的这个问题。
    lincanbin
        64
    lincanbin  
       2015-05-05 13:46:36 +08:00
    @iyaozhen 引号过滤然后直接拼接SQL语句是个不推荐的做法了,现在PHP官方建议使用PDO类或者mysqli类来替代mysql系列函数。
    也就是参数绑定,这样做的话,SQL命令与参数会分两次传到MySQL的socket,MySQL根据接收顺序就可以识别出命令和参数,从而避免在参数中构造命令(也就是SQL注入)。
    PDO的话可以参考这个
    https://github.com/lincanbin/PHP-PDO-MySQL-Class
    est
        65
    est  
    OP
       2015-05-05 13:55:43 +08:00
    @iyaozhen 逻辑老师呢?

    “只要改成A密码用B密码也能登录,说明是该php网站一定是明文保存密码的。”

    反过来一定成立吗?
    iyaozhen
        66
    iyaozhen  
       2015-05-05 14:00:08 +08:00
    @lincanbin 嗯,谢谢。这个我了解过。产品线上是使用mysqli类或者框架自身的参数绑定的方式。拼 sql 的方式几年前已经交过学费了,不过感觉学费还是交的不够。。。
    iyaozhen
        67
    iyaozhen  
       2015-05-05 14:07:04 +08:00
    @est 非常抱歉,逻辑错误了。

    还有就是才疏学浅,以为都是使用 sql 直接判断的。
    WKPlus
        68
    WKPlus  
       2015-05-05 14:39:18 +08:00
    @est
    把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑。

    这句话补充是不是这样:
    1. 把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的且密码对比的时候用的是php的==符号
    2. 但是如果密码比较的时候用的是===,那么就算是明文保存的,上述探测手段也是发现不了的
    est
        69
    est  
    OP
       2015-05-05 15:21:59 +08:00
    @WKPlus 第一句话也不完全一定。万一别人恰好特别写了 1193131 是万能登录密码呢?

    第二句话理论是这样的。 但是既然都知道用 === 怎么还会用明文密码。。。。。。。
    WKPlus
        70
    WKPlus  
       2015-05-05 19:50:59 +08:00
    @est 如果1193131是万能密码的话,你“把你的密码设成 0x1234Ab,然后退出登录再登录,换密码 1193131 登录,如果登录成功,那么密码绝对是明文保存的没跑”这句话就不成立了呀

    我的那两句解释只是想把你原来那句话的隐含意思说出来
    est
        71
    est  
    OP
       2015-05-05 20:15:48 +08:00
    @WKPlus 这不很容易解决么。把密码改成任意密码,如果1193131也能登录,那么说明1193131就是万能密码。


    准确的说,顶楼给出的几个密码对,可以衍生展开,如果尝试几组都符合特征,那么可以得到明文密码/md5无盐加密的结论。
    RemRain
        72
    RemRain  
       2015-05-05 22:40:54 +08:00
    @gDD 所以说 PHP 密码比较要这样:"X$pass1" == "X$pass2"
    gDD
        73
    gDD  
       2015-05-05 22:57:17 +08:00
    @RemRain 天……上面的帖子你都白看了吗?最次最次用 "$pass1" === "$pass2" 或者 strcmp(),最好用 hash_equals() 啊。
    123123
        74
    123123  
       2015-05-07 14:10:44 +08:00
    @gDD 只要最前方加个X就不会转换成数字进行比较,说的也没错就是了,不过加个=不是更方便么。。
    mahone3297
        75
    mahone3297  
       2015-05-07 22:08:33 +08:00
    这个帖子很赞,学习了。。。
    mingyun
        76
    mingyun  
       2015-05-11 21:40:00 +08:00
    果真脑洞打开,不过'240610708' ,'QNKCDZO'这种字符是怎么发现的?
    fhefh
        77
    fhefh  
       2015-10-17 21:48:14 +08:00
    学习了 mark~~
    wusuopuBUPT
        78
    wusuopuBUPT  
       2015-10-17 23:58:51 +08:00
    @est 原来如此!
    Kratoshy
        79
    Kratoshy  
       2015-12-08 15:16:31 +08:00
    var_dump(md5('240610708') === md5('QNKCDZO'));
    这个是 false 吧?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1501 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 16:29 PVG 00:29 LAX 09:29 JFK 12:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86