代码审计思路之PHP代码审计
×0 前言
进行PHP代码审计时,关注点与目标明确对提升审计效率至关重要。分析本文将分享PHP代码审计的源码一些思路和方法,帮助在审计过程中更加系统地发现潜在问题。分析
×1 前期工作,源码需要的工具
使用集成环境PHPStorm可以提高代码编写与调试的效率。静态代码扫描工具如Fotify有助于快速识别代码中的分析vscode爬虫源码问题,降低误报率。源码seay和CodeQl是分析源代码审计与自动化代码审计的强大工具,其中CodeQl为非商业的源码开源选择。Xcheck是分析一款专注于检测业务代码安全风险的工具,特别适用于寻找由不可信输入引发的源码安全漏洞。
×3 明确目标
在进行审计前,分析首先要明确审计的源码目的,可能有三种情况:提升审计经验、分析寻找可利用的源码漏洞、挖掘0day或证书。不同目的下的审计侧重点不同,例如为了发现漏洞进行渗透测试,可以重点使用自动化工具,关注文件上传、包含、SQL注入等严重危害的漏洞。
一>所有资源获取
×4 判断是否是用了框架
了解是否使用了框架对审计过程至关重要,框架的结构通常更规整,易于定位关键函数集。对于使用了框架的项目,审计重点在于控制器(C)部分,因为大部分功能点都集中在控制器中。
PHP主流框架包括Laravel、剑网3 副本掉落源码攻略ThinkPHP、yii等,它们大多采用MVC设计模式。对于ThinkPHP,其目录结构在版本3和5有所不同,但控制器(C)仍是审计的关键。
4.2. Laravel框架
在Laravel框架中,审计重点同样集中在控制器(C)中,因为大部分功能实现都在这里。
4.3. 如果没用框架
没有使用框架时,需要关注的点包括函数集文件、配置文件、安全过滤文件、index文件等。函数集文件通常包含function或common关键字,配置文件中可能包含config关键字,安全过滤文件对审计至关重要。
×5 了解路由
了解路由有助于快速定位漏洞位置。对于框架如Thinkphp,其路由规则清晰,审计时可通过路由直接访问漏洞方法。不同模式的路由配置(普通模式、混合模式、强制模式)需了解清楚,以便更好地定位和利用。
×6 审计
在审计前,可以使用自动化工具如xcheck、Fotify、qq小程序云开发源码codeql等进行初步扫描。根据报告验证审计发现,然后按类型深入审计,如SQL注入、XSS、CSRF、SSRF、XML外部实体注入等。
6.1. 鉴权
对于权限认证的审计,主要关注是否存在越权访问和未授权访问情况,通常后台管理是需要权限认证的地方。
6.2. 按照漏洞类型审计
根据漏洞类型定位可能存在漏洞的地方,如SQL注入、XSS、CSRF、SSRF、XML外部实体注入等,然后回溯验证参数可控性,快速定位漏洞。
6.2.1. SQL注入
审计时,重点关注是否存在字符串拼接并可被用户控制的SQL语句。
6.2.2. XSS漏洞
注意直接输出用户输入的地方,检查数据输出函数和全局拦截器、过滤器。
6.2.3. CSRF漏洞
CSRF攻击利用场景通常涉及敏感功能,审计时寻找生成随机token和token验证的逻辑。
6.2.4. SSRF漏洞
审计时注意访问端口、协议和内网IP的闲鱼群控系统源码是什么限制,以及使用file、tl_exec、popen等关键词,回溯参数可控性。
6.2.. 任意文件下载/下载漏洞审计
关注fget、file_get_contents、readfile、parse_ini_file、highlight_file、file、fopen、readfile、fread等函数,验证变量可控性。
6.2.. 任意文件删除
审计时搜索rmdir、unlink等函数,确保变量可控。
6.2.. 任意文件写入
注意copy、file_put_contents、fwrite等函数,检查可控变量。
6.2.. 会话认证漏洞
审计会话认证漏洞时,需关注cookie生成逻辑、用户身份验证方式,确保会话状态安全。
6.2.. 反序列化漏洞
审计时注意全局搜索serialize,检查是否存在可控变量。
将一个指针 free 两次之后会发生什么?
当一个在 C 语言中通过 malloc 动态分配的类似会计公司的网站源码内存,被 free 释放后,再进行第二次释放,这种行为被称为 double free,它在软件中常被视为一种潜在的二进制漏洞。一个具体的例子来自一道过去的 0ctf 竞赛,旨在通过逆向工程来理解其可能带来的风险。程序源代码可以在 github 上找到,环境为ubuntu . x_,使用了ida, pwntools, pwndbg等工具进行分析。
在逆向后的代码中,注意到关键点是,即使一个指针被 free 一次后,如果未被置空,它仍可能在后续执行中被误用,导致 double free。正确的做法是将空指针设置为 NULL,以保证安全。此外,代码中涉及了一个固定的存储区域,存储着 note0 字符串的地址,通过 double free 改变这个地址,可以影响程序的控制流,比如覆盖 got 表。
漏洞利用过程包括信息泄漏、chunk 的动态管理(如unlink函数导致的内存合并)以及伪造堆块以实现任意位置的读写。特别是通过覆盖 got 表,可以将 free 函数重定向到 system(),从而造成任意代码执行。
总的来说,double free 不仅可能导致内存混乱,更可能成为恶意攻击的入口。因此,开发者在编程时务必谨慎处理内存的分配和释放,以防止此类漏洞的发生。
ç®å说说ConcurrentSkipListMap
åºæ¬ä»ç»
è·³è·è¡¨çæ§è´¨å¦ä¸ï¼
æåºå±çæ°æ®èç¹æç §å ³é®åkeyååºæåï¼
å å«å¤çº§ç´¢å¼ï¼æ¯ä¸ªçº§å«çç´¢å¼èç¹æç §å ¶å ³èçæ°æ®èç¹çå ³é®åkeyååºæåï¼
é«çº§å«ç´¢å¼æ¯å ¶ä½çº§å«ç´¢å¼çåéï¼
å¦æå ³é®åkeyå¨çº§å«level=içç´¢å¼ä¸åºç°ï¼å级å«level<=içææç´¢å¼é½å å«è¯¥keyã
è·³è·è¡¨ConcurrentSkipListMapçæ°æ®ç»æå¦ä¸å¾æ示ï¼ä¸å¾ä¸å ±æä¸å±ç´¢å¼ï¼æåºä¸ä¸ºæ°æ®èç¹ï¼åä¸å±ç´¢å¼ä¸ï¼ç´¢å¼èç¹ä¹é´ä½¿ç¨rightæéç¸è¿ï¼ä¸å±ç´¢å¼èç¹çdownæéæåä¸å±çç´¢å¼èç¹ã
æºç åææ ¸å¿å段åæhead æå node(BASE_HEADER) ç顶å±ç´¢å¼ã
/***Thetopmostheadindexoftheskiplist.*/privatetransientvolatileHeadIndex<K,V>head;BASE_HEADER 头ç»ç¹ï¼å³æ顶å±ç´¢å¼ç头èç¹çvalueå¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()Node éæå é¨ç±»ï¼å³æ°æ®èç¹
/***æ°æ®èç¹*/staticfinalclassNode<K,V>{ finalKkey;//æ°æ®èç¹çkeyvolatileObjectvalue;//æ°æ®èç¹çvaluevolatileNode<K,V>next;//æåä¸ä¸ä¸ªæ°æ®èç¹/***Createsanewregularnode.*/Node(Kkey,Objectvalue,Node<K,V>next){ this.key=key;this.value=value;this.next=next;}}Index éæå é¨ç±»ï¼å³æ®éç´¢å¼èç¹
/***æ®éç´¢å¼èç¹*/staticclassIndex<K,V>{ finalNode<K,V>node;//ç´¢å¼èç¹æåçæ°æ®èç¹finalIndex<K,V>down;//å½åç´¢å¼èç¹çæ£ä¸æ¹ç´¢å¼èç¹volatileIndex<K,V>right;//å½åç´¢å¼èç¹çå³ç´¢å¼èç¹/***Createsindexnodewithgivenvalues.*/Index(Node<K,V>node,Index<K,V>down,Index<K,V>right){ this.node=node;this.down=down;this.right=right;}}HeadIndex éæå é¨ç±»ï¼å³å½å级å«ç´¢å¼ç头èç¹
/***å½å级å«ç´¢å¼ç头èç¹*/staticfinalclassHeadIndex<K,V>extendsIndex<K,V>{ finalintlevel;//æå¤ç´¢å¼çº§å«/***nodeï¼å½åç´¢å¼æåçæ°æ®èç¹*downï¼å½åç´¢å¼èç¹çæ£ä¸æ¹ç´¢å¼èç¹*rightï¼å½åç´¢å¼èç¹çå³ç´¢å¼èç¹*levelï¼å½åç´¢å¼å¤´èç¹æå¤çç´¢å¼çº§å«*/HeadIndex(Node<K,V>node,Index<K,V>down,Index<K,V>right,intlevel){ super(node,down,right);this.level=level;}}æ¥è¯¢æ ¹æ®æå®çkeyæ¥è¯¢èç¹ï¼æºç å¦ä¸ï¼
publicVget(Objectkey){ //è°ç¨doGetæ¹æ³returndoGet(key);}/***çæ£å®ç°æ¥è¯¢æ¹æ³*/privateVdoGet(Objectkey){ if(key==null)thrownewNullPointerException();Comparator<?superK>cmp=comparator;outer:for(;;){ for(Node<K,V>b=findPredecessor(key,cmp),n=b.next;;){ Objectv;intc;if(n==null)breakouter;Node<K,V>f=n.next;if(n!=b.next)//inconsistentreadbreak;if((v=n.value)==null){ //nisdeletedn.helpDelete(b,f);break;}if(b.value==null||v==n)//bisdeletedbreak;if((c=cpr(cmp,key,n.key))==0){ @SuppressWarnings("unchecked")Vvv=(V)v;returnvv;}if(c<0)breakouter;b=n;n=f;}}returnnull;}å¨ä¸è¿°ä»£ç ä¸ï¼outerå¤çforèªæä¸ï¼é¦å æ¥çfindPredecessorï¼æ¥è¯¢æå®keyèç¹çå驱èç¹ã该æ¹æ³å¨ä¸é¢ç好å¤å°æ¹ä¼è°ç¨ï¼ä¾å¦æå ¥å ç´ ï¼å é¤å ç´ ä»¥åå é¤å ç´ å¯¹åºçç´¢å¼æ¶é½ä¼è°ç¨ã
findPredecessoræ¹æ³æºç å¦ä¸ï¼
/***ä½ç¨1ï¼æ¾å°key对åºèç¹çå驱èç¹ï¼ä¸ä¸å®çççå驱èç¹ï¼ä¹å¯è½æ¯å驱ç»ç¹çå驱èç¹*ä½ç¨2ï¼å é¤æ æçç´¢å¼ï¼å³è¦å é¤èç¹æ¶ï¼å°èç¹çç´¢å¼ä¹å é¤æ*/privateNode<K,V>findPredecessor(Objectkey,Comparator<?superK>cmp){ if(key==null)thrownewNullPointerException();//don'tpostponeerrorsfor(;;){ //r为qèç¹çå³æéæåçèç¹ï¼r为å½åæ¯è¾èç¹,æ¯æ¬¡é½æ¯è¾rèç¹çkeyè·æ¥æ¾çkeyç大å°å ³ç³»for(Index<K,V>q=head,r=q.right,d;;){ if(r!=null){ Node<K,V>n=r.node;Kk=n.key;//该èç¹å·²ç»å é¤ï¼éè¦å é¤å ¶å¯¹åºçç´¢å¼if(n.value==null){ //该èç¹å·²ç»å é¤ï¼éè¦å é¤å ¶å¯¹åºçç´¢å¼if(!q.unlink(r))break;//restartr=q.right;//rereadrcontinue;}//å½åæ¥æ¾çkeyæ¯rèç¹çkey大ï¼æ以rãqèç¹é½åå³ç§»å¨if(cpr(cmp,key,k)>0){ q=r;r=r.right;continue;}}//å½qçä¸æ¹ç´¢å¼èç¹ä¸ºç©ºï¼å说æå·²ç»å°æ°æ®èç¹å±äºï¼éè¦éåºè¿è¡åç»æ¥æ¾å¤çif((d=q.down)==null)returnq.node;/***æ¤æ¶å½åæ¥æ¾çkeyå°äºrèç¹çkeyï¼éè¦å¾ä¸ä¸çº§ç´¢å¼æ¥æ¾*dèç¹èµå¼ä¸ºä¸ºqèç¹ä¸ºæ£ä¸æ¹èç¹ï¼å³ä¸ä¸çº§ç´¢å¼çæ£ä¸æ¹èç¹*/q=d;r=d.right;}}}findPredecessoræ¹æ³çæ¥æ¾è¿ç¨å¾ç¤ºå¦ä¸ï¼å设è¦æ¥æ¾èç¹6
ç±äºå½årèç¹çkeyæ¯æ¥è¯¢çkeyå°ï¼æ以ï¼rãqèç¹é½åå³ç§»å¨ï¼å³æ§è¡å¦ä¸ä»£ç ï¼
//å½åæ¥æ¾çkeyæ¯rèç¹çkey大ï¼æ以rãqèç¹é½åå³ç§»å¨if(cpr(cmp,key,k)>0){ q=r;r=r.right;continue;}æ¤æ¶rèç¹æåçæ°æ®èç¹ä¸ºï¼èç¹çkeyæ¯6èç¹çkey大ï¼æ¤æ¶éè¦æ§è¡å¦ä¸ä»£ç ï¼
/***æ¤æ¶å½åæ¥æ¾çkeyå°äºrèç¹çkeyï¼éè¦å¾ä¸ä¸çº§ç´¢å¼æ¥æ¾*dèç¹èµå¼ä¸ºä¸ºqèç¹ä¸ºæ£ä¸æ¹èç¹ï¼å³ä¸ä¸çº§ç´¢å¼çæ£ä¸æ¹èç¹*/q=d;r=d.right;æ¤æ¶rèç¹æåçæ°æ®èç¹ä¸º5ï¼5èç¹çkeyæ¯6èç¹çkeyå°ï¼qãrèç¹åå³ç§»å¨ï¼å¦ä¸å¾æ示
æ¤æ¶rèç¹æåçæ°æ®èç¹ä¸ºï¼èç¹çkeyæ¯6èç¹çkey大ï¼åçéè¦å¾ä¸çº§ç´¢å¼èµ°ï¼å¦ä¸å¾æ示ï¼
æ¤æ¶rèç¹æåçæ°æ®èç¹ä¸ºï¼èç¹çkeyæ¯6èç¹çkey大ï¼åçéè¦å¾ä¸çº§ç´¢å¼èµ°ï¼ä½æ¯æ¤æ¶ä¸ä¸çº§ç´¢å¼ä¸ºç©ºäºï¼å³(d = q.down) == nulläºï¼æ¤æ¶æ§è¡ç代ç å¦ä¸ï¼ è¿åqç´¢å¼æåçèç¹ï¼å³è¿åèç¹5.
//å½qçä¸æ¹ç´¢å¼èç¹ä¸ºç©ºï¼å说æå·²ç»å°æ°æ®èç¹å±äºï¼éè¦éåºè¿è¡åç»æ¥æ¾å¤çif((d=q.down)==null)returnq.node;以ä¸å°±æ¯æ¹æ³findPredecessorçæ¥æ¾æµç¨ï¼å±ä»¬æ¥ç继ç»çä¸é¢çdoGetæ¹æ³
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()0é¦å åå§åbãnãfä¸ä¸ªèç¹ï¼å¦ä¸å¾æ示
åç°æ¤æ¶nèç¹æåçèç¹å°±æ¯è¦æ¥è¯¢çèç¹ï¼äºæ¯æ§è¡å¦ä¸ä»£ç ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()1ç´æ¥è¿ånèç¹çvalueå¼ãæ¥è¯¢æä½å®æã
æå ¥è·³è·è¡¨çæå ¥æä½å以ä¸åç§æ åµï¼
æ åµ1ï¼è·³è·è¡¨å åå¨keyä¸è´å ç´ ï¼åæ¿æ¢
æ åµ2ï¼æå ¥æ°å ç´ ï¼æ é¡»ç»æ°å ç´ çæç´¢å¼èç¹
æ åµ3ï¼æå ¥æ°å ç´ ï¼éè¦ç»æ°å ç´ çæç´¢å¼èç¹ï¼ä¸ç´¢å¼é«åº¦ < maxLevel
æ åµ4ï¼æå ¥æ°å ç´ ï¼éè¦ç»æ°å ç´ çæç´¢å¼èç¹ï¼ä¸ç´¢å¼é«åº¦ > maxLevel
æºç å¦ä¸ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()2é¦å è¿æ¯è·æ¥è¯¢æä½ç±»ä¼¼ï¼è°ç¨findPredecessoræ¹æ³å æ¥æ¾å°å¾ æå ¥keyçå驱èç¹ï¼ä¸¾ä¸ªä¾åï¼ä¾å¦æ们æ³è¦æå ¥èç¹7ï¼å¦ä¸å¾æ示ï¼
æ¥çè·æ¥è¯¢æä½ä¸æ ·çæ¥éª¤å¦ä¸ï¼ç´æ¥çå¾ï¼
æ¤æ¶rèç¹æåæ°æ®èç¹1ï¼èç¹1çkeyå°äºå¾ æå ¥çèç¹7çkeyï¼äºæ¯èç¹qãråæ¶åå³ç§»å¨ã
æ¤æ¶rèç¹æåæ°æ®èç¹ï¼èç¹çkey大äºå¾ æå ¥èç¹7çkeyï¼äºæ¯å¾ä¸ä¸å±ç´¢å¼ç»§ç»æ¥æ¾ï¼æ§è¡ç代ç å¦ä¸ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()3åé¢çæä½ç±»ä¼¼
æ¤æ¶rèç¹çkey大äºå¾ æå ¥çèç¹6çkeyï¼ä½æ¯qèç¹çdownæé已为空ï¼æ¤æ¶ç´æ¥è¿åqèç¹æåçèç¹5ã
æ¥çåå°doPutæ¹æ³ï¼å æ¥æ¥çouter循ç¯ï¼å¦ä¸ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()4é¦å åå§åä¸ä¸ªèç¹bãnãfï¼nèç¹ä¸ºbèç¹çä¸ä¸ä¸ªèç¹ï¼èfèç¹ä¸ºnèç¹çä¸ä¸ä¸ªèç¹ï¼å¦ä¸å¾æ示
æ¥çæ¯è¾èç¹nä¸å¾ æå ¥çkeyç大å°ï¼æ¤æ¶nèç¹çkeyå°äºå¾ æå ¥èç¹çkeyï¼äºæ¯bãnãfä¸ä¸ªèç¹ååä¸ç§»å¨å¦ä¸å¾æ示
æ¤æ¶nèç¹çkey大äºå¾ æå ¥çkeyï¼æ¤æ¶æ§è¡å¦ä¸ä»£ç ï¼éè¿casæ¹å¼ä¿®æ¹bèç¹çä¸ä¸ä¸ªèç¹ä¸ºzèç¹ï¼æ¥çè·³åºouter循ç¯ã
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()5ç¶åæ们ç¥édoPutå©ä¸ç代ç æ éå°±æ¯å¤ææ¯å¦ç»æ°æå ¥çèç¹zå建索å¼ï¼å¦æéè¦å建对åºçç´¢å¼ã
é¦å éè¿int rnd = ThreadLocalRandom.nextSecondarySeed();计ç®åºä¸ä¸ªéæºæ°ï¼æ¥çè¿è¡å¦ä¸å¤æï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()6å¦ærnd & 0x) == 0å°±ç»æ°æå ¥çzèç¹å建索å¼ï¼æ们ç¥é0x = å³æé«ä½åæåä¸ä½ä¸º1ï¼å ¶ä½å ¨é¨æ¯0ï¼
æ¡ä»¶ï¼(rnd & 0x) == 0ä»ä¹æ¶åæç«ï¼
rndè¿ä¸ªéæºæ°æä½ä½åæé«ä½åæ¶æ¯0çæ¶åï¼æ¡ä»¶æç«ï¼æ¦çæ¯1/4
举个ä¾åï¼ä¾å¦rnd = = 3æ¡ä»¶å°±æç«ã
å¦ææ¡ä»¶æç«çè¯ï¼æ¥ç计ç®å°åºç»zèç¹å建å 级索å¼ï¼ä»£ç å¦ä¸ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()7éè¿whileæ¡ä»¶((rnd >>>= 1) & 1) != 0满足å 次就å建å 级索å¼ãä¾å¦ï¼
rnd = 计ç®åºæ¥çlevel => 3
rnd = 计ç®åºæ¥çlevel => 8
ç¶åæ¥çæ¯è¾è®¡ç®åºæ¥çzèç¹çç´¢å¼è·ç°æçè·³è·è¡¨çç´¢å¼çº§å«å¤§å°ã
æ åµä¸ï¼zèç¹è®¡ç®åºæ¥çç´¢å¼levelæ¯è·³è·è¡¨çlevelå°
æ åµäºï¼zèç¹è®¡ç®å¤ççç´¢å¼levelæ¯è·³è·è¡¨çlevel大ãæ¤æ¶ä¼éæ©æç»çlevel为åæ¥çè°è¡¨çlevel + 1
æ åµä¸
ç»zèç¹å建索å¼çæ¥éª¤å¦ä¸å¾æ示ï¼æ¤æ¶zèç¹çç´¢å¼è¿æ²¡æå å ¥è·³è·è¡¨ç°æçç´¢å¼éåä¸
æ¥ç继ç»æ§è¡splice循ç¯ï¼ä»£ç å¦ä¸ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()8åå§åqãrèç¹å¦ä¸å¾æ示
æ¤æ¶rèç¹çkeyæ¯æ°æå ¥zèç¹ï¼å³7èç¹å°ï¼äºæ¯ä¸¤ä¸ªèç¹qãté½åå³ç§»å¨å¦ä¸å¾æ示
æ¤æ¶rèç¹çkeyæ¯æ°æå ¥zèç¹ï¼å³7èç¹å¤§ï¼æ§è¡å¦ä¸ä»£ç ï¼
/***Specialvalueusedtoidentifybase-levelheader*/privatestaticfinalObjectBASE_HEADER=newObject()9æ¤æ¶rèç¹çkeyæ¯æ°æå ¥zèç¹ï¼å³7èç¹å°ï¼äºæ¯ä¸¤ä¸ªèç¹qãté½åå³ç§»å¨å¦ä¸å¾æ示
æ¤æ¶rèç¹çkeyæ¯æ°æå ¥zèç¹ï¼å³7èç¹å¤§,åçï¼ç´æ¥çå¾
æ åµäº
è·æ åµä¸ç±»ä¼¼ï¼è¿éå°±ä¸ä¸ä¸ç»å¾äº
å é¤å é¤æ¹æ³å®æçä»»å¡å¦ä¸ï¼
设置æå®å ç´ value为null
å°æå®nodeä»nodeé¾è¡¨ç§»é¤
å°æå®nodeçindexèç¹ ä» å¯¹åºç index é¾è¡¨ç§»é¤
/***æ°æ®èç¹*/staticfinalclassNode<K,V>{ finalKkey;//æ°æ®èç¹çkeyvolatileObjectvalue;//æ°æ®èç¹çvaluevolatileNode<K,V>next;//æåä¸ä¸ä¸ªæ°æ®èç¹/***Createsanewregularnode.*/Node(Kkey,Objectvalue,Node<K,V>next){ this.key=key;this.value=value;this.next=next;}}0åæ ·ï¼é¦å éè¿findPredecessoræ¹æ³æ¥æ¾å°è¦å é¤keyçå驱èç¹ï¼å°±ä¸ä¸ä¸ç»å¾äºï¼ç´æ¥çæ¾å°çå驱èç¹çå¾ï¼å¦ä¸ï¼
æ¥æ¯è¾nèç¹çkeyä¸å¾ å é¤çkeyç大å°ï¼æ¤æ¶nèç¹çkeyå°äºå¾ å é¤çkeyï¼å³7èç¹çkeyï¼äºæ¯å°bãnãfä¸ä¸ªèç¹é½åå³ç§»å¨ï¼å¦ä¸å¾ï¼
æ¤æ¶nèç¹çkeyè·å¾ å é¤çkeyä¸æ ·ï¼äºæ¯æ§è¡å¦ä¸ä»£ç ï¼
/***æ°æ®èç¹*/staticfinalclassNode<K,V>{ finalKkey;//æ°æ®èç¹çkeyvolatileObjectvalue;//æ°æ®èç¹çvaluevolatileNode<K,V>next;//æåä¸ä¸ä¸ªæ°æ®èç¹/***Createsanewregularnode.*/Node(Kkey,Objectvalue,Node<K,V>next){ this.key=key;this.value=value;this.next=next;}}1æååè°ç¨findPredecessoræ¸ æ¥æ æçç´¢å¼ï¼å³ä¸é¢å é¤çèç¹çç´¢å¼ã
/***æ°æ®èç¹*/staticfinalclassNode<K,V>{ finalKkey;//æ°æ®èç¹çkeyvolatileObjectvalue;//æ°æ®èç¹çvaluevolatileNode<K,V>next;//æåä¸ä¸ä¸ªæ°æ®èç¹/***Createsanewregularnode.*/Node(Kkey,Objectvalue,Node<K,V>next){ this.key=key;this.value=value;this.next=next;}}2éç¹é å¦ä¸ä»£ç åå é¤ç´¢å¼çï¼
/***æ°æ®èç¹*/staticfinalclassNode<K,V>{ finalKkey;//æ°æ®èç¹çkeyvolatileObjectvalue;//æ°æ®èç¹çvaluevolatileNode<K,V>next;//æåä¸ä¸ä¸ªæ°æ®èç¹/***Createsanewregularnode.*/Node(Kkey,Objectvalue,Node<K,V>next){ this.key=key;this.value=value;this.next=next;}}3æ们ç¥éå¨ä¸é¢å·²ç»å°å¾ å é¤ç7èç¹çvalue置为nulläºï¼ç´æ¥çå¾ï¼
æ¤æ¶rèç¹çkeyå°äºå¾ å é¤èç¹çkeyï¼äºæ¯rãqèç¹é½åå³ç§»å¨ã
æ¤æ¶r,nèç¹æåçæ°æ®èç¹çvalueå¼ä¸ºnulläºæ¯æ§è¡ä¸é¢çq.unlink(r)代ç ï¼å°qçå³æéæårçå³æéæåçèç¹ï¼å³å°±æ¯å é¤äºè¯¥levelä¸ç7èç¹çç´¢å¼èç¹ï¼å¦ä¸å¾æ示
æ¤æ¶rèç¹çkey大äºå¾ å é¤èç¹çkeyï¼äºæ¯å¾ä¸ä¸ç´¢å¼èµ°ï¼å¦ä¸å¾æ示
æ¤æ¶rèç¹çkeyå°äºå¾ å é¤èç¹çkeyï¼äºæ¯rãqèç¹é½åå³ç§»å¨ã
æ¤æ¶r,nèç¹æåçæ°æ®èç¹çvalueå¼ä¸ºnulläºæ¯æ§è¡ä¸é¢çq.unlink(r)代ç ï¼å°qçå³æéæårçå³æéæåçèç¹ï¼å³å°±æ¯å é¤äºè¯¥levelä¸ç7èç¹çç´¢å¼èç¹ï¼å¦ä¸å¾æ示
åç»æä½åçï¼æç»å°7èç¹çç´¢å¼ä¸ä¸å é¤å®ï¼æç»çå¾ä¸æ示
house of storm 的利用
作者:hope 合天智汇利用 mallopt 和 mmap 构建 House of Storm
首先,通过 mallopt 函数关闭 fastbin 功能,然后利用 mmap 动态分配一块地址空间,范围在 0x-0x。通过 open("/dev/urandom",0) 获取随机数,然后在地址 0x 开始写入 个字节,填充异或后的随机数。 接下来的 for 循环中,不断将 mmap 地址空间填充异或后的随机数,操作的输入 size 限定在 0xc 到 0x 之间。写入后的堆块地址和 size 会通过异或操作存储到同一地址段。 show 函数的限制 初始状态下,由于 show 函数的条件,程序无法直接输入信息,需要进行相应的修改才能输出结果。 edit 功能中的漏洞 edit 功能允许输入的 size 值必须是通过 add 时指定的 size 减去 0xc,因为这 0xc 的空间会被自动填充数据,但意外地多填充了 0 字节,导致 off-by-null 漏洞。这种漏洞被利用来实现 chunk shrink。利用 off-by-null 漏洞实现 chunk shrink
编辑部分解释了 off-by-null 漏洞是如何影响 size 域,以及为何需要构造特定的堆块大小以绕过 unlink 检测。 编辑后的堆块构造旨在构造两个 largebin 大小的堆块,通过 off-by-null 改变堆块的大小并触发 unlink 操作,实现堆块的堆叠。利用 unsortbin 和 largebin 的攻击
攻击策略包括伪造 unsortbin 中的堆块,以实现任意地址的堆块分配。通过调整bk指针和 size 值,能够控制链表遍历过程,获取目标堆块。总结与实践
这道题目展示了如何利用 House of Storm 技术,涉及的知识点包括 unsortbin 的操作、unlink 检测规避以及堆块重叠等。在学习过程中,建议深入阅读源码,并对相关概念进行归纳和总结。 最后,作者希望读者在实践中保持警惕,确保网络安全,所有行为后果自负。鸿蒙轻内核M核源码分析:LibC实现之Musl LibC
本文探讨了LiteOS-M内核中Musl LibC的实现,重点关注文件系统与内存管理功能。Musl LibC在内核中提供了两种LibC实现选项,使用者可根据需求选择musl libC或newlibc。本文以musl libC为例,深度解析其文件系统与内存分配释放机制。
在使用musl libC并启用POSIX FS API时,开发者可使用文件kal\libc\musl\fs.c中定义的文件系统操作接口。这些接口遵循标准的POSIX规范,具体用法可参阅相关文档,或通过网络资源查询。例如,mount()函数用于挂载文件系统,而umount()和umount2()用于卸载文件系统,后者还支持额外的卸载选项。open()、close()、unlink()等文件操作接口允许用户打开、关闭和删除文件,其中open()还支持多种文件创建和状态标签。read()与write()用于文件数据的读写操作,lseek()则用于文件读写位置的调整。
在内存管理方面,LiteOS-M内核提供了标准的POSIX内存分配接口,包括malloc()、free()与memalign()等。其中,malloc()和free()用于内存的申请与释放,而memalign()则允许用户以指定的内存对齐大小进行内存申请。
此外,calloc()函数在分配内存时预先设置内存区域的值为零,而realloc()则用于调整已分配内存的大小。这些函数构成了内核中内存管理的核心机制,确保资源的高效利用与安全释放。
总结而言,musl libC在LiteOS-M内核中的实现,通过提供全面且高效的文件系统与内存管理功能,为开发者提供了强大的工具集,以满足不同应用场景的需求。本文虽已详述关键功能,但难免有所疏漏,欢迎读者在遇到问题或有改进建议时提出,共同推动技术进步。感谢阅读。
[redis 源码走读] maxmemory 数据淘汰策略
Redis 是一个内存数据库,通过配置 `maxmemory` 来限定其内存使用量。当 Redis 主库内存超出限制时,会触发数据淘汰机制,以减少内存使用量,直至达到限制阈值。
当 `maxmemory` 配置被应用,Redis 会根据配置采用相应的数据淘汰策略。`volatile-xxx` 类型配置仅淘汰设置了过期时间的数据,而 `allkeys-xxx` 则淘汰数据库中所有数据。若 Redis 主要作为缓存使用,可选择 `allkeys-xxx`。
数据淘汰时机发生在事件循环处理命令时。有多种淘汰策略可供选择,从简单到复杂包括:不淘汰数据(`noeviction`)、随机淘汰(`volatile-random`、`allkeys-random`)、采样淘汰(`allkeys-lru`、`volatile-lru`、`volatile-ttl`、`volatile-freq`)以及近似 LRU 和 LRU 策略(`volatile-lru` 和 `allkeys-lru`)。
`noeviction` 策略允许读操作但禁止大多数写命令,返回 `oomerr` 错误,仅允许执行少量写命令,如删除命令 `del`、`hdel` 和 `unlink`。
`volatile-random` 和 `allkeys-random` 机制相对直接,随机淘汰数据,策略相对暴力。
`allkeys-lru` 策略根据最近最少使用(LRU)算法淘汰数据,优先淘汰最久未使用的数据。
`volatile-lru` 结合了过期时间与 LRU 算法,优先淘汰那些最久未访问且即将过期的数据。
`volatile-ttl` 策略淘汰即将过期的数据,而 `volatile-freq` 则根据访问频率(LFU)淘汰数据,考虑数据的使用热度。
`volatile-lru` 和 `allkeys-lru` 策略通过采样来近似 LRU 算法,维护一个样本池来确定淘汰顺序,以提高淘汰策略的精确性。
总结而言,Redis 的数据淘汰策略旨在平衡内存使用与数据访问需求,通过灵活的配置实现高效的数据管理。策略的选择应基于具体应用场景的需求,如数据访问模式、性能目标等。
2024-11-30 09:28
2024-11-30 09:19
2024-11-30 09:16
2024-11-30 07:54
2024-11-30 07:17